c++ - 列表初始化是隐式转换吗?

标签 c++ c++11 language-lawyer list-initialization

#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <vector>

class Base{
public:
    virtual ~Base() {}

};

class Derived: public Base { };

int main(){

    int arr[10];
    Derived d;
    Base *p = &d;

    std::map<std::type_index, std::string> proper_name = {
        {typeid(int), "int"}, {typeid(double), "double"}, {typeid(float), "float"}, {typeid(char), "char"},
        {typeid(Base), "Base"}, {typeid(Derived), "Derived"}, {typeid(std::string), "String"},
        {typeid(int[10]), "Ten int Array"}, {typeid(p), "Base Pointer"}};

}

我试图理解此列表初始化中发生的隐式转换。来自 13.3.1.7 N3337的:

When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:

  1. Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.

  2. If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.

8.5.4 :

A constructor is an initializer-list constructor if its first parameter is of type std::initializer_list<E> or reference to possibly cv-qualified std::initializer_list<E> for some type E, and either there are no other parameters or else all other parameters have default arguments

所以the following std::map 的构造函数列表表示

map (initializer_list<value_type> il, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()) ;

是候选函数,value_type在本例中是 pair<const type_index, std::string> 。最后来自13.3.3.1.5 :

If the parameter type is std::initializer_list<X> or “array of X”135 and all the elements of the initializer list can be implicitly converted to X, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to X.

因此,只要花括号列表的元素隐式转换为 pair<const type_index, std::string> ,这就是一个有效的转换。 。但这些元素本身也是花括号列表。 Pair不采用初始化列表构造函数,from here看来来自大括号初始化列表的复制初始化使用 13.3.1.7 的第二部分来构造对象。所以如下:

pair<const type_index, std::string> p = {typeid(int), "int"}

变成:

pair<const type_index, std::string> p(typeid(int), "int")

但这是否被视为隐式转换?如何将双参数构造函数的使用视为隐式转换?标准对此有何评论?

最佳答案

你的结论

pair<const type_index, std::string> p = {typeid(int), "int"};

变成了

pair<const type_index, std::string> p(typeid(int), "int");

不准确,因为第一个语句是复制列表初始化,而第二个语句是直接初始化。两者是相同的,除了如果选择显式构造函数,则复制列表初始化的格式不正确(并且前者不允许缩小转换)。 p>

因此,如果所讨论的 pair 构造函数定义为

template<class U1, class U2>
explicit constexpr pair(U1&& x, U2&& y);

直接初始化仍然会成功,但复制列表初始化会失败。从正下方引用您引用的[over.match.list]部分

In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.

<小时/>

除此之外,你所说的其他一切都是正确的。 pair 构造函数是隐式转换,因为构造函数不是显式,并且根据[over.match.list]< 的第二个项目符号考虑重载决策。/em> 因为 pair 没有初始化列表构造函数。

关于c++ - 列表初始化是隐式转换吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34912221/

相关文章:

c++ - 从 Windows 系统菜单中删除“移动”和“关闭”命令,而不会丢失功能

c++ - 在 C++ 中实现正则表达式

c++ - 什么时候应该在函数返回值上使用 std::move?

c++ - 了解常量表达式

c++ - 对 C++ 中的 std::get_money 和 std::put_money 的混淆

c++ - 从 C++ 中的文本文件中提取和使用特定数据

c++ - 为什么 std::not1() 通过 const 引用而不是值来获取参数?

python - 小数缓存是在 Python 规范中定义的还是一个实现细节?

c++ - 如何在 log4cplus 中添加自定义过滤器?

c++ - 为什么右值 STL 容器中的元素 getter 返回左值?