2016-10-28 81 views
4

我有一个类widget
我有一个抽象类base与衍生物derived_aderived_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设有右值,它则可以变成std::vector<unique_ptr<base>>的列表。
我的印象是,这可以通过模板化ctor来实现,但是,尽管大量使用Google,但我并不知道如何完全实现我的目标。

请注意,看起来类模板解决此题刻:

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,但你可以使用可变参数模板:

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它在叮当3.8和gcc 6.1上工作http:/ /coliru.stacked-crooked.com/a/31d9cc1434505b55 – themagicalyang