繁体   English   中英

大括号构造函数更喜欢使用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_tchar的缩小转换),因此在考虑使用size + value构造函数之前就使用了它。

因此,要回答编辑后的问题:不,您不能在不命名向量类型的情况下创建向量。 但是在C ++ 17中,您可以使用类模板参数推导并只需编写return std::vector(i, c);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM