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

时间:2017-05-24 15:26:26

标签: 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});
}

我原本认为initializer_list的{​​{1}}参数已经足够了,并且会导致将元组键插入指定的元组值关联。显然,编译器不同意。

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

3 个答案:

答案 0 :(得分: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));

调用构造函数

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...>);

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

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

或(在评论中由Nicol指出的C ++ 17中)

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

等同于

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

并调用构造函数

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

另请注意,AFAIK无法明确使用std::initializer_list<int>来实现此功能。原因很简单,pair<ThreeTuple,ThreeTuple>(地图的value_type)没有合适的构造函数。

答案 1 :(得分:6)

  

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

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

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

并且您无法从{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&&);

答案 2 :(得分:0)

类似的东西在 C++17 中会起作用:

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