C++ 类括号初始化被误解为std::initializer\u列表,而不是复制构造

C++ 类括号初始化被误解为std::initializer\u列表,而不是复制构造,c++,c++11,gcc,C++,C++11,Gcc,考虑以下C++11代码: #include <initializer_list> struct MyStruct { MyStruct() {} MyStruct(const MyStruct& other) {} void doStuff() const {} }; int main() { MyStruct a; auto b{a}; a.doStuff(); b.doStuff(); return 0

考虑以下C++11代码:

#include <initializer_list>

struct MyStruct {
    MyStruct() {}
    MyStruct(const MyStruct& other) {}
    void doStuff() const {}
};

int main() {
    MyStruct a;
    auto b{a};

    a.doStuff();
    b.doStuff();
    return 0;
}
#包括
结构MyStruct{
MyStruct(){}
MyStruct(const MyStruct&other){}
void doStuff()常量{}
};
int main(){
我的结构a;
自动b{a};
a、 doStuff();
b、 doStuff();
返回0;
}
我原以为
b
MyStruct
的一个实例,副本是由
a
构建的,但是当使用GCC 4.9.1编译时,
b
是一个
std::initializer
。GCC 8.2按照预期编译了该文件

注意我在锁销上举了一个例子:


你能解释一下这两个编译器版本之间的区别吗?(或者标准的状态是什么?)< P> > P >这是C++ 11中的预期行为:

在以下情况下,将自动构造std::initializer\u list对象: ... 大括号的init列表绑定到auto,包括在ranged for循环中

因此,当您将
{x1,x2,…,xn}
分配给“auto”时,如果所有值都具有相同的类型,您将得到类型为
std::initializer\u list
的对象(为了简单起见,我在这里跳过引用和cv):

auto a={5};//std::初始值设定项列表
自动b{5};//std::初始值设定项列表
自动c={1,2};//std::初始值设定项列表
自动d{1,2};//std::初始值设定项列表
然而,在C++17中,这一点被改变了。增加了以下规则:

  • 对于复制列表初始化,自动扣减将推导出 如果列表中的所有元素都具有相同的 类型,或格式不正确
  • 对于直接列表初始化,如果列表只有一个元素,则自动推断将推断出一个T,如果有多个元素,则自动推断将是格式错误的 一个因素
因此,当您使用C++17兼容编译器编译时,您将得到

auto a = {42};   // std::initializer_list<int>
auto b {42};     // int
auto c = {1, 2}; // std::initializer_list<int>
auto d {1, 2};   // error, too many
auto a={42};//std::初始值设定项列表
自动b{42};//int
自动c={1,2};//std::初始值设定项列表
自动d{1,2};//错误,太多了

我相信gcc 8.2在这种情况下不能正确处理-std=c++11这是c++11中的一个bug,在c++14中修复了它。看起来GCC 8.2正在考虑新规则,即使你正在用C++ 11标志编译。 新角色说:

对于直接列表初始化:

  • 对于只有一个元素的带括号的init列表,自动推断将 从该条目开始
  • 对于包含多个元素的大括号init列表,自动推断的格式将不正确
就你而言:

MyStruct a;
auto b{a};
它遵循第一条规则,这就是它编译没有问题的原因


老一代的GCC 4.91没有实现这些新的规则,所以默认的是它认为是<代码> STD::IngaliSeriSList./P>但是为什么编译器的两个版本之间的差异呢?有趣的怪癖!我想我们可以称之为怪癖:D谢谢你的澄清!

MyStruct a;
auto b{a};