9

在更新一些代码以使用统一初始化时,我认为这将是现在“旧式”括号样式的现代替代品。我知道情况并非总是如此(明显的例子,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
};

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

4

2 回答 2

6

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

于 2014-01-24T19:34:09.647 回答
3

约翰内斯的回答很有用,但让我详细说明一下为什么会发生这种情况。

您描述的这两种更改都会通过使其从聚合变为非聚合来影响您的类。参见 C++11 (N3485) § 8.5.1/1:

聚合是一个数组或一个类(第 9 条),没有用户提供的构造函数(12.1),没有用于非静态数据成员的大括号或等号初始化器(9.2),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),也没有虚函数(10.3)。

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

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

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

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

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

列表初始化定义的新提议标准(如 Johannes 的链接中所示)提供了列表中单个元素的优先级情况,并且它具有(或非常接近)正在初始化的对象的类型。之后,聚合初始化将是重中之重。

于 2014-01-24T19:44:56.337 回答