简体   繁体   English

元组到元组的 std::map 并使用 emplace

[英]std::map of tuple to tuple and using emplace

Consider the following code, compiled with g++ 7.0.1 (-std=c++17):考虑以下使用 g++ 7.0.1 (-std=c++17) 编译的代码:

#include <map>
#include <tuple>

int main()
{
    // Create an alias for a tuple of three ints
    using ThreeTuple=std::tuple<int,int,int>;
    // Create an alias for a map of tuple to tuple (of three ints)
    using MapThreeTupleToThreeTuple=std::map<ThreeTuple,ThreeTuple>;

    MapThreeTupleToThreeTuple m;

    // The following does NOT compile
    m.emplace({1,2,3},{4,5,6});

    // ..., and neither does this
    m.emplace(std::piecewise_construct,{1,2,3},{4,5,6});
}

I would have thought that the initializer_list arguments to map::emplace() would have sufficed and would have resulted in the insertion of the tuple key to tuple value association as specified.我原以为map::emplace()initializer_list参数就足够了,并且会导致按照指定将元组键插入到元组值关联中。 Apparently, the compiler disagrees.显然,编译器不同意。

Of course creating a tuple explicitly (ie, ThreeTuple{1,2,3} instead of just {1,2,3} ) and passing that to map::emplace() solves the problem, but why can't the initializer lists be passed directly to map::emplace() which would automatically forward them to the tuple constructors?当然,显式创建一个元组(即ThreeTuple{1,2,3}而不仅仅是{1,2,3} )并将其传递给map::emplace()可以解决问题,但是为什么初始化程序不能列出直接传递给map::emplace() ,它会自动将它们转发给元组构造函数?

AFAIK, no changes in C++17 matter in this context. AFAIK,在这种情况下,C++17 没有任何变化。 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.正如 NathanOliver 和 Barry 所解释的那样, {1,2,3}不能被推断为具有任何类型,因此不能与模板参数匹配。 You must provide the arguments for the constructor of ThreeTuple as deducible types, ie您必须为ThreeTuple的构造函数提供ThreeTuple推导类型的参数,即

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在这种特殊情况下,您甚至可以省略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)或(如 Nicol 在评论中指出的在 C++17 中)

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.另请注意,AFAIK 您无法通过显式使用std::initializer_list<int> The reason is simply that there is not suitable constructor for pair<ThreeTuple,ThreeTuple> (the value_type of your map).原因很简单, pair<ThreeTuple,ThreeTuple> (地图的value_type )没有合适的构造函数。

but why can't the initializer lists be passed directly to map::emplace()但是为什么不能将初始化列表直接传递给map::emplace()

Because initializer lists aren't expressions and so they don't have types.因为初始化列表不是表达式,所以它们没有类型。 The signature for emplace() is just:emplace()的签名只是:

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

and you can't deduce a type from {1,2,3} .并且您无法从{1,2,3}推断出类型。 You couldn't in C++11 and you still can't in C++1z.你不能在 C++11 中,你仍然不能在 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.此规则的唯一例外是如果模板参数的格式为std::initializer_list<T> ,其中T是模板参数。

In order for m.emplace({1,2,3},{4,5,6});为了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&&);

类似的东西可以在C++17

m.try_emplace({1,2,3},4,5,6);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM