当对象没有数据成员时,统一初始化无法复制

时间:2014-01-24 19:23:50

标签: c++ c++11 copy-constructor uniform-initialization

在更新一些代码以使用统一初始化时,我认为它将成为现在“旧式”括号样式的现代替代品。我知道情况并非总是如此(显而易见的例子,vector<int>)但是我偶然发现了另一个我不理解的差异。

class Object {
    public:
        Object() = default;
        Object(const Object&) = default;
};

int main() {
    Object o;
    Object copy{o}; // error
    Object copy2(o); // OK
}

无法在clang3.5下编译并出现错误:(在gcc下也失败)

error: excess elements in struct initializer

Object有两个不同的变化使这项工作成功。向其添加数据成员,或为其提供空复制构造函数体

class Object {
    private:
        int i; // this fixes it
    public:
        Object() = default;
        Object(const Object&) { } // and/or this fixes it as well
};

我不明白为什么这些应该有所作为。

2 个答案:

答案 0 :(得分:6)

这是一个已知错误,希望在C ++ 17中修复(不适用于C ++ 14,请参阅http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467)。您的结构是一个聚合,因此要使用{someElement}对其进行初始化,至少需要一个数据成员,如您所发现的那样。尝试提供operator int();,您将看到它编译。

答案 1 :(得分:3)

约翰内斯的答案很有用,但让我详细说明它为什么会出现。

您描述的两个更改都会影响您的课程,使其从聚合变为聚合。参见C ++ 11(N3485)§8.5.1/ 1:

  

聚合是一个数组或类(第9节),没有用户提供的构造函数(12.1),没有用于非静态数据成员的 brace-or-equal-initializers (9.2),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),也没有虚函数(10.3)。

定义为= default的构造函数被认为不是用户定义的。

然后,在第8.5.4节中进入列表初始化,我们看到:

  

对象或类型T的引用的列表初始化定义如下:

     
      
  • 如果T是聚合,则执行聚合初始化
  •   

然后是一堆“其他......”部分。因此,更改其中任何一个都允许调用构造函数而不是执行聚合初始化。

列表初始化定义的新建议标准(在Johannes的链接中可见)提供了列表中单个元素的优先级大小写,并且它具有(或非常接近)对象类型的类型初始化。之后,聚合初始化将成为最重要的优先事项。