派生类型的大括号初始化

Brace initialisation of derived types

我想要一个类型,它只是一个对象列表,可以派生自某些基础 class。即调用者得到StuffMoreStuff的列表(由Stuff派生),至少可以对Stuff部分进行操作

这听起来像 std::vector< std::unique_ptr< Stuff > >。但是,我也想用大括号初始化器初始化它,这就是我画空白的地方。

这或多或少是我正在尝试的:

#include <vector>
#include <memory>
#include <string>

struct Stuff {
    std::string s1;
    std::string s2;
};

using AllStuff = std::vector< std::unique_ptr< Stuff > >;

AllStuff const MyStuff = {
    std::make_unique<Stuff>( Stuff{"1", "one"} )
};

struct MoreStuff : public Stuff {
    std::string s3;
};

AllStuff const AllMoreStuff = {
    std::make_unique<Stuff>( MoreStuff{"2", "two", "too"} )
};

或者,更确切地说,类似的东西。输入越少(用于向向量添加更多 Stuff)越好。

理论上会有一种方法将 AllStuffAllMoreStuff 的引用作为参数,并能够使用 s1s2 从它。其他方法只能使用 AllMoreStuff 并能够使用 s3(通过适当使用 dynamic_cast<MoreStuff*>(...))。

然而,理论和现实还没有完全吻合,如果能帮助确定如何支撑初始化派生对象列表,我们将不胜感激。

您不能将 std::initializer_liststd::unique_ptr 一起使用,因为 std::unique_ptr 是不可复制的,并且使用 std::initializer_list 进行初始化意味着复制。

您可以切换到 std::shared_ptr 并向您的结构添加构造函数:

struct Stuff {
    Stuff(const std::string& s1, const std::string& s2)
        : s1(s1)
        , s2(s2)
    {}

    std::string s1;
    std::string s2;
};

using AllStuff = std::vector< std::shared_ptr< Stuff > >;

AllStuff const MyStuff = {
    std::make_shared<Stuff>("1", "one")
};

struct MoreStuff : Stuff {
    MoreStuff(const std::string& s1, const std::string& s2, const std::string& s3)
        : Stuff(s1, s2)
        , s3(s3)
    {}

    std::string s3;
};

AllStuff const AllMoreStuff = {
    std::make_shared<MoreStuff>("2", "two", "too")
};

使用 C++17,您可以编写

MoreStuff{{"2", "two"}, "too"}

因为聚合规则已更改为允许基数 classes(参见 P0017)。

对于 C++14 及更早版本,MoreStuff 不是聚合,因为存在基 class,聚合初始化不适用,因此您必须提供构造函数来做你想做的事。

但是,即使您使用 C++17 编译器,初始化 vector 的其余代码也无法工作。如果包含的类型不可复制,则无法使用其 initializer_list 构造函数初始化 vector,有关详细信息,请参阅 this question