2016-10-28 2 views
4

У меня есть класс 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; 
}; 

И будет называться так:

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

Однако это решение швы unnessesarry подробны и удобной для пользователей на всех, особенно при предоставлении мультипликатор типы:

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

Вместо этого, я бы предпочел использовать по строкам

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

так что widget снабжена списком rvalues, что он затем может превратиться в std::vector<unique_ptr<base>>.
У меня сложилось впечатление, что это может быть достигнуто с помощью шаблонов для ctor, но, несмотря на интенсивный поиск в Google, я не знаю, как точно достичь моей цели.

Пожалуйста, обратите внимание, что шаблон класса решение, которое будет выглядеть Tike это:

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

нежелательно, так как мне нужно предоставить некоторые deriveds с параметрами.

+0

К сожалению - я не думал о проблемах ООП в то время ... Но не могли бы вы добиться более простого кодирования с использованием фабричного класса? '' class wf {static std :: unique_ptr make_a (/ * возможно, некоторые аргументы * /) {...}; ...}; '', а затем '' widget w; w.visuals ({wf :: make_a(); ...}) ''? – BitTickler

+2

только немного «менее» подробный. AFAIK вам не нужно «двигаться» в 'push_back' – Hayt

+0

Ну, попробовав мою фабричную идею вроде флопа. Кажется, '' std :: unique <> '' имеет проблемы с обработкой абстрактных базовых классов. Кто бы мог предположить, что они внутренне пытаются сделать копии? :) – BitTickler

ответ

5

К сожалению, вы не можете использовать 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; 
}; 

Demo

или в C++ 17, с откидным выражением:

template <typename ... Ts> 
    explicit widget(Ts&&... params) 
    { 
     (members.emplace_back(std::make_unique<Ts>(std::forward<Ts>(params))), ...); 
    } 
+4

Вместо 'std :: move' я бы предпочел использовать' std :: forward'. – themagicalyang

+0

@themagicalyang это дало мне '' std :: forward ': в MSVC не найдено перегруженной функции', в то время как версия с 'std :: move' отлично работает –

+1

@JanNilsFerner Это работает на clang 3.8 и gcc 6.1 http://coliru.stacked-crooked.com/a/31d9cc1434505b55 – themagicalyang

Смежные вопросы