首先,C++ 语法规则使括号初始化列表,
的尾随可选。引用dcl.init/1
声明者可以为被声明的标识符指定一个初始值。标识符指定正在初始化的变量。[dcl.init] 其余部分中描述的初始化过程也适用于其他语法上下文指定的初始化,例如函数参数的初始化([expr.call])或返回值的初始化([stmt.return] )。
initializer:
brace-or-equal-initializer
( expression-list )
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
braced-init-list:
{ initializer-list ,opt }
{ designated-initializer-list ,opt }
{ }
其次,您几乎无法覆盖重载解析系统。std::initializer_list
如果您使用此类语法并且此类std::initializer_list
构造函数可用,它将始终使用构造函数。
dcl.init.list/2:
如果构造函数的第一个参数是 std::initializer_list 类型或对某些类型 E 的可能有 cv 限定的 std::initializer_list 的引用,并且没有其他参数或所有其他参数,则构造函数是初始化列表构造函数参数具有默认参数。
[注意:初始化列表构造函数比列表初始化中的其他构造函数更受青睐([over.match.list])......
下面的程序打印Using InitList
:
#include <iostream>
#include <initializer_list>
struct X{
X(std::initializer_list<double>){ std::cout << "Using InitList\n"; }
X(int){ std::cout << "Using Single Arg ctor\n"; }
};
int main(){
X x{5};
}
尽管这5
是 type 的文字int
,但选择单参数构造函数应该是有意义的,因为它是完美匹配的;并且std::initializer_list<double>
构造函数想要一个double
. 但是,规则有利于std::initializer_list<double>
它,因为它是一个初始化列表构造函数。
结果,即使是下面的程序也会因为缩小转换而失败:
#include <iostream>
#include <initializer_list>
struct Y{
Y(std::initializer_list<char>){ std::cout << "Y Using InitList\n"; }
Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; }
};
int main(){
Y y1{4777};
Y y2{577,};
Y y3{57,7777};
}
针对您在下面的评论,“如果 std::initializer_list 没有重载,或者它不是第一个构造函数的参数怎么办? ” - 然后重载决议不会选择它。演示:
#include <iostream>
#include <initializer_list>
struct Y{
Y(int, std::initializer_list<double>){ std::cout << "Y Using InitList\n"; }
Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; }
};
int main(){
Y y1{4};
Y y2{5,};
Y y3{5,7};
}
印刷:
Y Using Double Arg ctor
Y Using Double Arg ctor
Y Using Double Arg ctor
如果没有可用的初始化器列表构造器,那么{initializer-list...,}
初始化器几乎会根据dcl.init/16退回到直接初始化,其语义由dcl.init/16的前一段涵盖