std::map of tuple to tuple and using emplace

AFAIK, no changes in C++17 matter in this context. As explained by NathanOliver and Barry, {1,2,3} cannot be deduced to have any type and hence cannot be matched against a template argument. You must provide the arguments for the constructor of ThreeTuple as deducible types, i.e.

m.emplace(std::piecewise_construct,
          std::forward_as_tuple(1,2,3),
          std::forward_as_tuple(4,5,6));

which calls the constructor

template<typename T1, typename T2>
template<typename... Args1, typename... Args2 >
std::pair<T1,T2>::pair(std::piecewise_construct_t,
                       std::tuple<Args1...>, std::tuple<Args2...>);

In this particular case, you can even omit the std::piecewise_construct

m.emplace(std::forward_as_tuple(1,2,3),
          std::forward_as_tuple(4,5,6));

or (in C++17 as pointed out by Nicol in a comment)

m.emplace(std::tuple(1,2,3), std::tuple(4,5,6));

which are equivalent to

m.emplace(ThreeTuple(1,2,3), ThreeTuple(4,5,6));

and call the constructor

template<typename T1, typename T2>
std::pair<T1,T2>::pair(const&T1, const&T2);

Note also that AFAIK you cannot get this working by using std::initializer_list<int> explicitly. The reason is simply that there is not suitable constructor for pair<ThreeTuple,ThreeTuple> (the value_type of your map).


but why can't the initializer lists be passed directly to map::emplace()

Because initializer lists aren't expressions and so they don't have types. The signature for emplace() is just:

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );

and you can't deduce a type from {1,2,3}. You couldn't in C++11 and you still can't in C++1z. The only exception to this rule is if the template parameter is of the form std::initializer_list<T> where T is a template parameter.

In order for m.emplace({1,2,3},{4,5,6}); to work, you'd need a signature like:

std::pair<iterator,bool> emplace(key_type&&, mapped_type&&);

Tags:

C++

C++17