[英]Why wasn't a double curly braces syntax preferred for constructors taking a std::initializer_list
[英]Curly braces constructor prefers initializer_list over better match. Why?
#include <vector>
using std::size_t;
struct Foo
{
Foo(size_t i, char c) {}
};
Foo Bar1()
{
size_t i = 0;
char c = 'x';
return { i, c }; // good
}
std::vector<char> Bar2()
{
size_t i = 0;
char c = 'x';
return { i, c }; // bad
}
https://wandbox.org/permlink/87uD1ikpMkThPTaw
警告:在{}内将'i'的转换范围从'std :: size_t {aka long unsigned int}'缩小为'char'
显然,它尝试使用vector的initializer_list。 但是为什么不使用更好的匹配vector<char>(size_t, char)
呢?
我可以在return语句中使用所需的构造函数,而无需再次编写类型吗?
因为initializer_list构造函数(如果可能)优先于其他构造函数。 这是为了减少边缘情况的混乱-特别是,您期望它使用的特定矢量构造函数被认为很容易被偶然选择。
具体而言,该标准在16.3.1.7“通过列表初始化进行初始化” [over.match.list]中进行了说明(最新草案,N4687):
(1)当非聚合类类型T的对象被列表初始化,使得11.6.4指定根据本节中的规则执行重载解析时,重载解析在两个阶段中选择构造函数:
- 最初,候选函数是类T的初始化器列表构造函数(11.6.4),参数列表由作为单个参数的初始化器列表组成。
- 如果找不到可行的初始化器列表构造函数,则再次执行重载解析,其中候选函数是T类的所有构造器,并且参数列表由初始化器列表的元素组成。
因此,如果您执行std::vector<char>( i, c )
,则此部分根本不适用,因为它不是列表初始化。 应用正常的重载分辨率,找到并使用(size_t, char)
构造函数。
但是,如果您执行std::vector<char>{ i, c }
,则这是列表初始化。 首先尝试使用构造函数列表构造函数,并且(initializer_list<char>)
构造函数是一个匹配项(即使它涉及从size_t
到char
的缩小转换),因此在考虑使用size + value构造函数之前就使用了它。
因此,要回答编辑后的问题:不,您不能在不命名向量类型的情况下创建向量。 但是在C ++ 17中,您可以使用类模板参数推导并只需编写return std::vector(i, c);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.