【问题标题】:Enable default initializer list constructor启用默认初始化列表构造函数
【发布时间】:2015-07-10 07:15:35
【问题描述】:

我相信现代 C++ 初始化器列表对于初始化对象非常有用,以至于无需定义自己的构造函数:

struct point
{
    float coord[3];
};

point p = {1.f, 2.f, 3.f}; // nice !

但是,当我的类从另一个类继承时,这不起作用:

template<typename T>
class serializable
{
    protected:
        serializable() = default;
    ...
    // other stuff
}

struct point : public serializable<point>
{
    float coord[3];
};
point p = {1.f, 2.f, 3.f}; // Doesn't work :(

我尝试将point() = default; 添加到我的点数课程中,但这也不起作用。如何仍然使用初始化列表初始化点?

【问题讨论】:

    标签: c++ c++11 inheritance initializer-list list-initialization


    【解决方案1】:

    您的原始案例依赖于聚合初始化 [dcl.init.list]:

    类型 T 的对象或引用的列表初始化定义如下:
    ...
    — 否则,如果T 是聚合,则执行聚合初始化

    聚合和聚合初始化在哪里,来自 [dcl.init.aggr],强调我的:

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

    当聚合被初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素 被视为聚合成员的初始值设定项,按递增的下标或成员顺序。每个 成员是从相应的初始化子句复制初始化的。

    但现在,由于point 有一个基类(serializable&lt;point&gt;),point 不再是聚合,不再支持聚合初始化。

    解决办法就是简单的提供这样一个构造函数来初始化point

    struct point : public serializable<point>
    {
        template <typename... T>
        point(T... ts) 
        : coord{ts...}
        { } 
    
        float coord[3];
    };
    

    【讨论】:

    • 感谢您清晰详细的回答。这让我想知道为什么标准是这样的。我猜这是因为构造函数不会被调用......也许在某些情况下它们可能是构造函数和列表初始化之间的冲突。但是,与所有构造函数一样,= default 应该不会引起任何问题
    • @Amxx 如果基类有成员怎么办?如果这些成员是默认可构造的怎么办?目前尚不清楚在所有这些情况下应该做什么“正确的事情”——因此标准选择不猜测。
    • 您还可以将数据填充到成员或基类中,例如struct point_data { float coord[3]; },然后拥有一个基于{} 构造它的“完美转发构造函数”。
    猜你喜欢
    • 1970-01-01
    • 2011-06-17
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多