传递派生类型列表以将其存储为成员

Jan*_*ner 5 c++ polymorphism templates c++11 c++14

我上课了widget.
我有一个抽象类base与衍生物derived_a,derived_b等等.

我希望widget保留任意数量的派生对象,base以便以后以多态方式使用它们.

我的第一次尝试看起来像这样:

#include <vector>
#include <ostream>
#include <iostream>
#include <memory>

class widget {
public:
    explicit widget(std::vector<std::unique_ptr<base>>&& params) :
    members {std::move (params)}
    {            
    }

private:
    std::vector<std::unique_ptr<base>> members;
};
Run Code Online (Sandbox Code Playgroud)

并将被称为这样:

std::vector<std::unique_ptr<base>> v;
v.push_back(std::move(std::make_unique<derived_a>()));
widget w (std::move(v));
Run Code Online (Sandbox Code Playgroud)

但是,这个解决方案接口冗长,而不是用户友好,特别是在提供多种类型时:

std::vector<std::unique_ptr<base>> v;
v.push_back(std::move(std::make_unique<derived_a>()));
v.push_back(std::move(std::make_unique<derived_b>()));
v.push_back(std::move(std::make_unique<derived_c>()));
v.push_back(std::move(std::make_unique<derived_a>()));
v.push_back(std::move(std::make_unique<derived_b>()));
v.push_back(std::move(std::make_unique<derived_c>()));
widget w {std::move(v)};
Run Code Online (Sandbox Code Playgroud)

相反,我更喜欢沿着这条线使用

widget w {derived_a(), 
          derived_b(), 
          derived_c(), 
          derived_a(), 
          derived_b(), 
          derived_c()};
Run Code Online (Sandbox Code Playgroud)

因此,widget它提供了一个随后可以变成的右值列表std::vector<unique_ptr<base>>.
我的印象是,这可以通过模仿ctor来实现,但是,尽管谷歌搜索量很大,但我并不知道如何准确地实现我的目标.

请注意,类模板解决方案看起来像这样:

widget<derived_a, 
       derived_b, 
       derived_c, 
       derived_a, 
       derived_b, 
       derived_c> w;
Run Code Online (Sandbox Code Playgroud)

是不可取的,因为我需要提供一些参数派生.

Jar*_*d42 7

不幸的是,你不能使用initializer_list,但你可以使用variadic模板:

class widget {
public:
    template <typename ... Ts>
    explicit widget(Ts&&... params) 
    {
        int dummy[] =
            {0, (members.emplace_back(std::make_unique<Ts>(std::forward<Ts>(params))), 0)...};
        static_cast<void>(dummy); // avoid unused variable warning
    }

private:
    std::vector<std::unique_ptr<base>> members;
};
Run Code Online (Sandbox Code Playgroud)

演示

或者在C++ 17中,使用折叠表达式:

    template <typename ... Ts>
    explicit widget(Ts&&... params) 
    {
        (members.emplace_back(std::make_unique<Ts>(std::forward<Ts>(params))), ...);
    }
Run Code Online (Sandbox Code Playgroud)

  • 而不是`std :: move`我宁愿使用`std :: forward`. (4认同)