构造函数、初始化器列表以及g++和clang中的不同行为

Constructor, initializer list and different behaviour in g++ and clang

本文关键字:clang g++ 初始化 列表 构造函数      更新时间:2023-10-16

这是简化的代码:

#include <vector>
class VInitList
{
public:
    explicit VInitList(std::vector<int> v){}
};
int main()
{
    VInitList vil({{}});
}

并用g++5.2.1编译得到这个错误:

 error: call of overloaded ‘VInitList(<brace-enclosed initializer list>)’ is ambiguous
     VInitList vil({{}});
                       ^
main.cpp:6:5: note: candidate: VInitList::VInitList(std::vector<int>)
     VInitList(std::vector<int> v){}
     ^
main.cpp:3:7: note: candidate: constexpr VInitList::VInitList(const VInitList&)
     class VInitList
           ^
main.cpp:3:7: note: candidate: constexpr VInitList::VInitList(VInitList&&)

当我看到编译器错误时,我发现我错写了{{}}(是的,不要对我刻薄),但我仍然无法理解这个错误。IMHO编译器必须清除多余的{}或返回语法错误。

然后我尝试编译这个:

std::vector<int> v = {{{}}};

其按预期工作。

但是std::vector<int> v = {{{}}};不会按照你的想法去做;它用一个初始化为零的int元素初始化向量。这是因为int可以列表初始化:

int i{};   // assert(i == 0)

因此std::vector<int> v = {{{}}};被解析为:

std::vector<int> v = {{{}}};
                       ^-- int
                      ^-- initializer_list<int>
                     ^-- vector<int>

同样,如果你写

VInitList vil{{{}}};
               ^-- int
              ^-- vector<int>
             ^-- VInitList 

所包含的vector<int>具有初始化为零的1个元素。(initializer_list<int>阶段可以省略,因为vector(initializer_list<int>)构造函数是非explicit)。

因此VInitList vil({{}});可以解析为:

VInitList vil({{}});
               ^-- int
              ^-- vector<int>

或作为

VInitList vil({{}});
               ^-- vector<int>
              ^-- VInitList

在第一种情况下,vector具有1个元素;在第二种情况下,它是空的。gcc拒绝您的代码也是好的。

Clang只是将其解析为前者;我不确定哪一个是正确的。