成员初始值设定项列表错误的统一初始化

Uniform initialization on member initializer list error

本文关键字:错误 初始化 列表 成员      更新时间:2023-10-16

我在这个 C++11 代码上收到编译错误,但我不知道为什么。这是代码:

#include <condition_variable>
class NonCopiableClass
{
std::condition_variable condition_;
};
struct NonCopiableStruct
{
std::condition_variable condition_;
};
class Test
{
public:
Test() : 
myClass{},
myStruct{}
{};
private:
NonCopiableClass myClass;
NonCopiableStruct myStruct;
};

Visual Studio 2015 失败,并出现以下错误:

错误 C2280:"std::condition_variable::condition_variable(const std::condition_variable &)":尝试引用已删除的函数 1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\mutex(550):注意:请参阅"std::condition_variable::condition_variable"的声明。

如果我将Test constructor更改为不使用C++11 统一初始化Struct它编译正常。

Test() : 
myClass{},
myStruct() // <--- CHANGE
{};

我不明白为什么Struct类型使用复制构造函数,但Class似乎没问题。它只发生在Struct拥有不可复制的成员时。

我还注意到,如果我在Test Class成员初始值设定项列表之外初始化Struct它有效:

int main()
{
NonCopiableStruct a{};   
return 0;
}

知道为什么这段代码失败吗?引擎盖下发生了什么?myClass初始化和myStruct初始化有什么区别?为什么如果在类成员initializer list上使用它不会编译,但我可以在外面使用它吗?我已经试过GCC,似乎还可以。

这似乎是一个MSVC错误。不同之处在于,struct版本是聚合版本,而class版本不是(由于默认的专用访问说明符)。

类版本由{}初始化的值。结构版本已聚合初始化。一个符合标准的编译器应该只列出初始化condition_{},因为你没有为它提供初始值设定项。

但是 MSVC 似乎偶然发现了这样一个事实,即聚合的成员是从初始值设定项列表中的相应初始值设定项进行复制初始化的。它似乎检查了副本c'tor,即使它不应该实际使用它。

这进一步得到了以下事实的支持:它知道在成员初始值设定项列表之外初始化相同类型的对象时该怎么做。