std ::元组到元组和使用emplace的映射

Mic*_*eyn 8 c++ 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});
}
Run Code Online (Sandbox Code Playgroud)

我本以为这些initializer_list参数map::emplace()已经足够了,并且会导致将元组键插入指定的元组值关联.显然,编译器不同意.

当然创建一个元组显式(即,ThreeTuple{1,2,3}而不是只是{1,2,3})并传递它来map::emplace()解决问题,但为什么不能将初始化列表直接传递给map::emplace()哪些会自动将它们转发给元组构造函数?

Wal*_*ter 8

AFAIK,在这种情况下,C++ 17没有任何变化.正如NathanOliver和Barry所解释的那样,{1,2,3}不能推断出任何类型,因此无法与模板参数匹配.您必须提供构造函数的参数ThreeTuple作为可推导类型,即

m.emplace(std::piecewise_construct,
          std::forward_as_tuple(1,2,3),
          std::forward_as_tuple(4,5,6));
Run Code Online (Sandbox Code Playgroud)

它调用构造函数

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...>);
Run Code Online (Sandbox Code Playgroud)

在这种特殊情况下,您甚至可以省略 std::piecewise_construct

m.emplace(std::forward_as_tuple(1,2,3),
          std::forward_as_tuple(4,5,6));
Run Code Online (Sandbox Code Playgroud)

或者(正如Nicol在评论中指出的C++ 17)

m.emplace(std::tuple(1,2,3), std::tuple(4,5,6));
Run Code Online (Sandbox Code Playgroud)

相当于

m.emplace(ThreeTuple(1,2,3), ThreeTuple(4,5,6));
Run Code Online (Sandbox Code Playgroud)

并调用构造函数

template<typename T1, typename T2>
std::pair<T1,T2>::pair(const&T1, const&T2);
Run Code Online (Sandbox Code Playgroud)

另请注意,AFAIK您无法通过std::initializer_list<int>显式使用来实现此功能.原因很简单,就是pair<ThreeTuple,ThreeTuple>(value_type你的地图)没有合适的构造函数.


Bar*_*rry 6

但为什么不能将初始化列表直接传递给 map::emplace()

因为初始化列表不是表达式,因此它们没有类型.签名emplace()只是:

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );
Run Code Online (Sandbox Code Playgroud)

你不能从中推断出一种类型{1,2,3}.你不能在C++ 11中,你仍然不能在C++ 1z.唯一的例外是,如果模板参数的形式为std::initializer_list<T>这里T是一个模板参数.

为了m.emplace({1,2,3},{4,5,6});工作,你需要一个签名,如:

std::pair<iterator,bool> emplace(key_type&&, mapped_type&&);
Run Code Online (Sandbox Code Playgroud)

  • @MichaelGoldshteyn请注意,有`initializer_list`并且有*初始化列表*.`initializer_list`可以从*初始化列表*构造,因为它知道类型应该是什么.普通模板类型不会失败. (2认同)