嵌套列表初始化如何转发其参数?



在对向量的初始化中

std::vector<std::pair<int, std::string>> foo{{1.0, "one"}, {2.0, "two"}};

我应该如何解释foo的构造?据我了解,

  1. 构造函数使用支撑初始化语法调用,因此重载vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );是首选并选择
  2. 的 推
  3. std::initializer_list<T>的模板参数std::pair<int, std::string>
  4. foo的每个元素都是一个std::pair。但是,std::pair没有超载接受std::initializer_list

我不太确定第 3 步。我知道内牙套不能解释为std::initializer_list,因为它们是异质的。标准中的什么机制实际上是构建foo的每个元素?我怀疑答案与将内括号中的参数转发到重载template< class U1, class U2 pair( U1&& x, U2&& y );有关,但我不知道这叫什么。

编辑

我认为提出相同问题的更简单方法是:当一个人这样做时

std::map<int, std::string> m = { // nested list-initialization
{1, "a"},
{2, {'a', 'b', 'c'} },
{3, s1}

如 CPP首选项示例所示,在标准中哪里说{1, "a"}{2, {'a', 'b', 'c'} }{3, s1}分别转发给构造函数以进行std::pair<int, std::string>

通常,表达式由内而外分析:内部表达式具有类型,然后这些类型决定外部运算符具有哪些含义以及要调用哪些函数。

但初始值设定项列表不是表达式,并且没有类型。因此,由内而外是行不通的。需要特殊的重载解析规则来考虑初始值设定项列表。

第一条规则是:如果构造函数的单个参数是某种initializer_list<T>,那么在第一轮重载解析中,只考虑这样的构造函数(over.match.list)。

第二条规则是:对于每个initializer_list<T>候选者(每个类可能有多个候选,每个候选项的T不同),检查每个初始值设定项是否可以转换为T,并且只有那些候选者保留在可行的地方(over.ics.list)。

这第二条规则基本上是,采用初始值设定项列表没有类型障碍并恢复由内而外的分析。

一旦重载解析决定应使用特定的initializer_list<T>构造函数,将使用复制初始化来初始化初始值设定项列表的类型为T的元素。

您混淆了两个不同的概念:

1) 初始值设定项列表

initializer_list<T>:主要用于集合的初始化。在这种情况下,所有成员都应属于同一类型。(不适用于std::pair)

例:

std::vector<int> vec {1, 2, 3, 4, 5};

2) 统一初始化

Uniform initialization:其中大括号用于构造和初始化一些对象,如结构、类(具有适当的构造函数)和基本类型(int、char 等)。

例:

struct X { int x; std::string s;}; 
X x{1, "Hi"}; // Not an initializer_list here.

话虽如此,要使用大括号初始值设定项初始化std::pair,您将需要一个接受两个元素的构造函数,即第一个和第二个元素,而不是std::initializer_list<T>。例如,在我的安装了VS2015的机器上,这个构造函数看起来像这样:

template<class _Other1,
class _Other2,
class = enable_if_t<is_constructible<_Ty1, _Other1>::value
&& is_constructible<_Ty2, _Other2>::value>,
enable_if_t<is_convertible<_Other1, _Ty1>::value
&& is_convertible<_Other2, _Ty2>::value, int> = 0>
constexpr pair(_Other1&& _Val1, _Other2&& _Val2) // -----> Here the constructor takes 2 input params
_NOEXCEPT_OP((is_nothrow_constructible<_Ty1, _Other1>::value
&& is_nothrow_constructible<_Ty2, _Other2>::value))
: first(_STD forward<_Other1>(_Val1)), // ----> initialize the first 
second(_STD forward<_Other2>(_Val2)) // ----> initialize the second
{   // construct from moved values
}

最新更新