最近我写了一个非常简单的课程。
class C
{
public:
void AddString(std::initializer_list<std::pair<const char*,int>> x)
{
//irrelevant
}
};
int main()
{
C c;
c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });
.... //other unimportant stuff
return 0;
}
令我惊喜的是,它编译并正常工作。有人可以向我解释一下编译器如何能够推导出std::pair
的嵌套支撑初始化器吗?我正在使用MSVS 2013。
答案 0 :(得分:9)
c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });
您正在传递 braced-init-list ,它本身包含嵌套的 brace-init-list 到AddString
。如果内部 braced-init-list 可以转换为std::initializer_list<std::pair<const char*,int>>
,则参数可以匹配std::pair<const char*,int>
参数。
这个过载解决过程分两步进行;首先尝试匹配带有std::pair
参数的std::initializer_list
构造函数。由于std::pair
没有这样的构造函数,因此第二步发生,其中std::pair<const char*,int>
的其他构造函数枚举为char const[2]
和int
作为参数。这将与以下pair
构造函数匹配,因为char const[2]
可隐式转换为char const *
,构造函数本身不是explicit
。
template< class U1, class U2 >
constexpr pair( U1&& x, U2&& y );
引用N3337 §13.3.1.7/ 1 [over.match.list]
当非聚合类类型
T
的对象被列表初始化(8.5.4)时,重载决策分两个阶段选择构造函数:
- 最初,候选函数是类T
的初始化列表构造函数(8.5.4),参数列表由初始化列表作为单个参数组成。
- 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类T
的所有构造函数,参数列表包含初始化列表。
如果初始化列表没有元素且
T
具有默认构造函数,则省略第一个阶段。 在复制列表初始化中,如果选择了explicit
构造函数,则初始化格式错误。