支持派生类型的初始化

时间:2017-12-11 20:04:09

标签: c++ c++14 list-initialization

我想有一个类型,它只是一个可以从某个基类派生的对象列表。也就是说,来电者会获得StuffMoreStuff(来自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作为参数,并且可以使用s1和{{1} } 从中。其他方法只需s2并且能够使用AllMoreStuff(通过适当使用s3)。

然而,理论和现实尚未完全排列,并且在确定如何支持初始化派生对象列表方面的任何帮助都将受到赞赏。

2 个答案:

答案 0 :(得分:1)

您不能将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")
};

答案 1 :(得分:1)

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

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

因为聚合规则已更改为允许基类(请参阅P0017)。

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

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