11

我在这个 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具有不可复制的成员的情况下。

我还注意到,如果我在成员初始化器列表的Struct外部初始化它可以工作:Test Class

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

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

4

1 回答 1

14

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

类版本是由 初始化的值{}。结构版本是聚合初始化的。符合要求的编译器应该只列出 initialize condition_with {},因为您没有为它提供初始化程序。

但是 MSVC 似乎绊倒了一个事实,即聚合的成员是从初始值设定项列表中的相应初始值设定项复制初始化的。它似乎检查了复制 c'tor,即使它不应该实际使用它。

当同类型的对象在成员初始化器列表之外被初始化时,它知道该怎么做,这进一步支持了这一点。

于 2018-01-11T07:52:47.463 回答