【问题标题】:Is list-initialization an implicit conversion?列表初始化是隐式转换吗?
【发布时间】:2016-04-27 00:25:35
【问题描述】:
#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. 如果找不到可行的初始化列表构造函数,则再次执行重载决议,其中候选函数是类 T 的所有构造函数,参数列表由初始化列表的元素组成。

8.5.4:

如果构造函数的第一个参数是 std::initializer_list&lt;E&gt; 类型或对某些类型 std::initializer_list&lt;E&gt; 的引用可能是 cv-qualified std::initializer_list&lt;E&gt;,并且没有其他参数或所有其他参数,则该构造函数是初始化列表构造函数有默认参数

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

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

是候选函数,value_type 在这种情况下是pair&lt;const type_index, std::string&gt;。最后来自13.3.3.1.5

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

所以只要花括号列表的元素隐式转换为pair&lt;const type_index, std::string&gt;,它就是有效的转换。但这些元素本身也是大括号列表。 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")

但这是否被视为隐式转换?如何将使用两个参数的构造函数视为隐式转换?这个标准的 cmets 是什么?

【问题讨论】:

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


    【解决方案1】:

    你的结论

    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);
    

    direct-initialization 仍然会成功,但 copy-list-initialization 会失败。从您引用的 [over.match.list] 部分的正下方引用

    在复制列表初始化中,如果选择了explicit 构造函数,则初始化格式错误。


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

    【讨论】:

    猜你喜欢
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    • 2021-12-19
    相关资源
    最近更新 更多