考虑使用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()
会自动将它们转发给元组构造函数吗?
答案 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);