2015-02-27 3 views
0

В C++ я хотел бы создать новый элемент (shared_ptr) для каждого типа, указанного в списке типов (и добавить результирующие указатели к вектору). В псевдокоде, это должно выглядеть примерно так:Как создать элемент для каждого типа в списке типов и добавить его в вектор в C++?

vector< shared_ptr<baseT> > v; 
foreach(type T: <derivedT1, derivedT2, ..., derivedTn>) 
{ 
    v.emplace_back(make_shared<T>()); 
} 

Есть краткое решение для этого с помощью std или boost (MPL, Fusion,?)?

Некоторые исследования:

  • я нашел что-то подобное в type visitor over typelist in c++. К сожалению, я в настоящее время не могу представить, как заменить sizeof с этой должности кодом создания из приведенного выше примера и как инкапсулировать необходимые определения для краткого использования.
  • В boost MPL и Fusion я еще не смог найти подходящий итерационный алгоритм, работающий только с типом (без экземпляра этого типа).

ответ

4

[Полное раскрытие: я разрабатываю Hana]

Отвечу, используя Hana библиотеку, которая еще не в Boost, но будет предложен для официального рассмотрения в ближайшее время. Hana объединяет функциональность MPL и Fusion под унифицированным интерфейсом.

#include <boost/hana.hpp> 
#include <memory> 
#include <vector> 


struct baseT { }; 
struct derivedT1 : baseT { }; 
struct derivedT2 : baseT { }; 
struct derivedT3 : baseT { }; 

int main() { 
    std::vector<std::shared_ptr<baseT>> v; 
    auto types = hana::tuple_t<derivedT1, derivedT2, derivedT3>; 
    hana::for_each(types, [&](auto t) { 
     // decltype(t)::type is derivedTk 
     using T = typename decltype(t)::type; 
     v.emplace_back(std::make_shared<T>()); 
    }); 
} 
+0

Я глубоко впечатлен лаконичностью и универсальностью вашего решения на основе ханы. Это было именно то, что я искал. - К сожалению, в настоящее время я не могу изменить среду разработки, которая отвечает требованиям hana (например, компилятор полностью соответствует стандарту C++ 14). Я с нетерпением жду, чтобы хана включилась в форсирование. –

+0

Я чувствую, что это именно то, что мне нужно. У меня есть список типов и хочу что-то сделать для каждого элемента в этом списке типов, например, по умолчанию - построить элемент каждого типа и вставить его в контейнер. это решает мою проблему элегантно. – ofloveandhate

+0

Я рад, что это помогает! –

1

Что-то типа следующего кода соответствует вашим потребностям?

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

using namespace std; 

#define TYPELIST1(t1) t1 
#define TYPELIST2(t1, t2) std::pair<t1, t2> 
#define TYPELIST3(t1, t2, t3) std::pair<t1, TYPELIST2(t2, t3)> 
#define TYPELIST4(t1, t2, t3, t4) std::pair<t1, TYPELIST3(t2, t3, t4)> 

template <typename T> 
struct add_obj { 
    template <typename Base> 
    static void make(std::vector<std::shared_ptr<Base>>& v) 
    { 
     v.emplace_back(std::make_shared<T>()); 
    } 
}; 

template <typename T1, typename T2> 
struct add_obj<std::pair<T1, T2>> { 
    template <typename Base> 
    static void make(std::vector<std::shared_ptr<Base>>& v) 
    { 
     v.emplace_back(std::make_shared<T1>()); 
     add_obj<T2>::make(v); 
    } 
}; 

struct Obj { Obj(int n) : value(n) {} int value; }; 
struct Obj1 : Obj { Obj1() : Obj(1) {} }; 
struct Obj2 : Obj { Obj2() : Obj(2) {} }; 

int main() 
{ 
    std::vector<shared_ptr<Obj>> v; 
    add_obj<Obj1>::make(v); 
    add_obj<TYPELIST3(Obj1, Obj2, Obj1)>::make(v); 
    for (auto p : v) { 
     std::cout << p->value << std::endl; 
    } 
} 
+0

Благодарим вас за предложение этого интересного и понятного решения, тем более, что оно зависит только от библиотеки std. Тем не менее, я предпочел бы более общее решение, позволяющее указывать 'emplace_back' (или другие утверждения, которые должны быть повторены для каждого типа) только один раз и около вызова для итерации по типам. –

+0

@Casten Scholtes: вы можете добавить параметр шаблона, который по умолчанию соответствует & std :: vector :: emplace_back. –

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

  • Нет связанных вопросов^_^