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

时间:2016-01-20 22:54:38

标签: 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"}};

}

我试图弄清楚这个列表初始化中发生的隐式转换。来自N3337的13.3.1.7

  

当非聚合类类型T的对象被列表初始化(8.5.4)时,重载决策分两个阶段选择构造函数:

     
      
  1. 最初,候选函数是类T的初始化列表构造函数(8.5.4),参数列表由初始化列表作为单个参数组成。

  2.   
  3. 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类T的所有构造函数,参数列表由初始化列表的元素组成。

  4.   

8.5.4

  

构造函数是初始化列表构造函数,如果它的第一个参数是std::initializer_list<E>类型,或者对于某些类型std::initializer_list<E>可能引用cv-qualified E,并且没有其他构造函数参数或所有其他参数都有默认参数

std::map的{​​{3}}构造函数列表表示

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

是候选函数,在这种情况下value_typepair<const type_index, std::string>。最后来自13.3.3.1.5

  

如果参数类型为std::initializer_list<X>或“X数组”135并且初始化列表的所有元素都可以隐式转换为X,则隐式转换序列最差将列表元素转换为X所需的转换。

因此,只要被括号列表的元素隐式转换为pair<const type_index, std::string>,它就是有效的转换。但这些元素也是支撑列表本身。 Pair没有使用初始化列表构造函数,the following似乎来自braced-init列表的复制初始化使用13.3.1.7的第二部分来构造对象。以下是:

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

变为:

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

但是这被认为是隐式转换吗?如何使用双参数构造函数作为隐式转换?标准的评论是什么?

1 个答案:

答案 0 :(得分:3)

你的结论

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

变为

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

不准确,因为第一个语句是 copy-list-initialization ,而第二个语句是 direct-initialization 。两者是相同的,只是如果选择explicit构造函数, copy-list-initialization 格式不正确(并且前者不允许缩小转换)。

因此,如果有问题的pair构造函数被定义为

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

直接初始化仍然会成功,但 copy-list-initialization 会失败。从你引用的 [over.match.list] 部分的正下方引用

  

在copy-list-initialization中,如果选择了explicit构造函数,则初始化是不正确的。

除此之外,你说的其他一切都是正确的。 pair构造函数是隐式转换,因为构造函数不是explicit,并且根据 [over.match.list] 的第二个项目考虑重载解析,因为{{ 1}}没有初始化列表构造函数。