大括号构造函数更喜欢使用initializer_list而不是更好的匹配.为什么? [英] Curly braces constructor prefers initializer_list over better match. Why?

查看:42
本文介绍了大括号构造函数更喜欢使用initializer_list而不是更好的匹配.为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#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{}

warning: narrowing conversion of 'i' from 'std::size_t {aka long unsigned int}' to 'char' inside { }

很显然,它尝试使用vector的initializer_list.但是为什么不使用匹配更好的 vector< char>(size_t,char)?

Obviously it tries to use the initializer_list of vector. But why doesn't it use the better match vector<char>(size_t, char) ?

是否可以在return语句中使用所需的构造函数,而无需再次编写类型?

Can i use the desired constructor in a return statement without writing the type again?

推荐答案

因为initializer_list构造函数(如果可能)优先于其他构造函数.这是为了减少边缘情况的混乱-特别是,您期望它使用的特定矢量构造函数被认为很容易被偶然选择.

Because initializer_list constructors, if at all possible, take precedence over other constructors. This is to make edge cases less confusing - specifically, this particular vector constructor that you expect it to use was deemed too easily selected by accident.

具体来说,该标准在16.3.1.7通过列表初始化进行初始化"中表示[over.match.list](最新草案,N4687):

Specifically, the standard says in 16.3.1.7 "Initialization by list-initialization" [over.match.list] (latest draft, N4687):

(1)当非聚合类类型T的对象被列表初始化,使得11.6.4指定根据本节中的规则执行重载解析时,重载解析在两个阶段中选择构造函数:

(1) When objects of non-aggregate class type T are list-initialized such that 11.6.4 specifies that overload resolution is performed according to the rules in this section, overload resolution selects the constructor in two phases:

  • 最初,候选函数是类T的初始化器列表构造函数(11.6.4),参数列表由作为单个参数的初始化器列表组成.
  • 如果找不到可行的初始值设定项列表构造函数,则再次执行重载解析,其中候选函数是T类的所有构造函数,并且参数列表由初始值设定项列表的元素组成.

因此,如果您执行 std :: vector< char>(i,c),则此部分根本不适用,因为它不是列表初始化.应用普通的重载分辨率,找到并使用(size_t,char)构造函数.

So if you do std::vector<char>( i, c ), this section does not apply at all, since it isn't list-initialization. Normal overload resolution is applied, the (size_t, char) constructor is found, and used.

但是,如果您执行 std :: vector< char> {i,c} ,这就是列表初始化.首先尝试使用初始化程序列表构造函数,并且(initializer_list< char>)构造函数是匹配项(即使它涉及从 size_t char <的缩小转换)/code>),因此在考虑使用size + value构造函数之前就可以使用它.

But if you do std::vector<char>{ i, c }, this is list-initialization. The initializer list constructors are tried first, and the (initializer_list<char>) constructor is a match (even though it involves the narrowing conversion from size_t to char), so it is used before the size+value constructor is ever considered.

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

So to answer the edited-in question: no, you can't create the vector without naming its type. But in C++17 you can use class template argument deduction and simply write return std::vector(i, c);

这篇关于大括号构造函数更喜欢使用initializer_list而不是更好的匹配.为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆