Jan Nils Ferner Jan Nils Ferner - 1 month ago 5
C++ Question

Pass a list of deriveds for storage as member

I have a class

widget
.

I have an abstract class
base
with derivates
derived_a
,
derived_b
, etc.

I want
widget
to hold an arbitrary amount of objects that are derivated from
base
in order to later use them polymorphically.

My first attempt looks like this:

#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;
};


And would be called like this:

std::vector<std::unique_ptr<base>> v;
v.push_back(std::move(std::make_unique<derived_a>()));
widget w (std::move(v));


However, this solution seams unnessesarry verbose and not user friendly at all, especially when providing multiple types:

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)};


Instead, I would prefer usage along the lines of

widget w {derived_a(),
derived_b(),
derived_c(),
derived_a(),
derived_b(),
derived_c()};


so that
widget
is provided with a list of rvalues that it then can turn into
std::vector<unique_ptr<base>>
.

I have the impression that this can be achieved through templating the ctor, but, despite intensive googling, I have no clue on how to achieve my goal exactly.

Please note that the class template solution that would look tike this:

widget<derived_a,
derived_b,
derived_c,
derived_a,
derived_b,
derived_c> w;


Is undesirable, as I need to provide some deriveds with parameters.

Answer

Unfortunately, you cannot use initializer_list, but you can use variadic template:

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

private:
    std::vector<std::unique_ptr<base>> members;
};

Demo