创建一个包含不同驱动器类元素的元组,其驱动器的构造函数接收一个int类型,该类型由其在元组中的索引确定

时间:2019-01-13 14:19:49

标签: c++ templates variadic-templates template-meta-programming stdtuple

我有一个基类,它的构造函数接收一个名为id的int类型,还有几个不同的派生类,它们的构造函数形式与基类相同。

现在,我想制作一个包含每个元素的元组,其构造函数接收一个由其在该元组中的索引确定的id。像下面的哑函数一样:

class Base(){
    Base(int id){}
}

class Derive1, Derived2...Derivedn : public Base(){
     Derive(int id):Base(id){}
}

auto make_derives_tuple()->decltype(...){
   //manually write each elements' index in the tuple seems too ugly and unnecessary
   return std::make_tuple(Derive1(0),Derived2(1),Derived3(2)...); 
}

如果派生类的数量为三个:

struct Base{
    Base(int id){
        id_=id;
    }
    int id_;
};

struct Derive:public Base{
    Derive(int id):Base(id){

    }
};


struct Derive2:public Base{
    Derive2(int id):Base(id){

    }
};

auto make_derive_tuple()->decltype (std::make_tuple(Derive(0),Derive2(1),Derive3(2))){
    //I want the int passed to the derived class's construor automatically generated according to it's position in the tuple
    return std::make_tuple(Derive(0),Derive2(1),Derive3(2));
}

但是在元组中手动编写每个元素的索引以传递给构造函数似乎太丑陋和不必要。有什么优雅的方法可以做到这一点吗?就像使用可变参数模板类或函数一样。

1 个答案:

答案 0 :(得分:1)

我没有一种优雅的方法来迭代简单的类,例如Derived1Derived2Derived3等。

但是如果您可以按照以下方式或以类似方式对衍生类进行模板化,添加模板索引,则有所不同

template <std::size_t>
struct Derived : public Base
 { Derived (int id) : Base{id} {} };

如果您还可以使用C ++ 14,则可以按以下方式使用std::make_index_sequence / std::index_sequence

template <std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
 { return std::make_tuple(Derived<Is+1u>{Is}...); }

template <std::size_t N>
auto make_derives_tuple ()
 { return make_helper(std::make_index_sequence<N>{}); }

以下是完整的编译示例

#include <tuple>
#include <utility>
#include <type_traits>

struct Base
 { Base (int) {} };

template <std::size_t>
struct Derived : public Base
 { Derived (int id) : Base{id} {} };

template <std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
 { return std::make_tuple(Derived<Is+1u>{Is}...); }

template <std::size_t N>
auto make_derives_tuple ()
 { return make_helper(std::make_index_sequence<N>{}); }

int main()
 {
   auto t = make_derives_tuple<3u>();

   using T0 = decltype(t);
   using T1 = std::tuple<Derived<1u>, Derived<2u>, Derived<3u>>;

   static_assert( std::is_same<T0, T1>::value, "!" );
 }

如果您无法对派生类进行模板化(添加索引),那么我能想象的最好是将所需的派生类作为模板可变参数列表传递给make_derived_tuple()

解决方案变成

template <typename ... Ts, std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
 { return std::make_tuple(Ts{Is}...); }

template <typename ... Ts>
auto make_derives_tuple ()
 { return make_helper<Ts...>(std::index_sequence_for<Ts...>{}); }

以下是完整的编译示例(其中我将重命名的类重命名为ABCD

#include <tuple>
#include <utility>
#include <type_traits>

struct Base
 { Base (int) {} };

struct A : public Base
 { A (int id) : Base{id} {} };

struct B : public Base
 { B (int id) : Base{id} {} };

struct C : public Base
 { C (int id) : Base{id} {} };

struct D : public Base
 { D (int id) : Base{id} {} };

template <typename ... Ts, std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
 { return std::make_tuple(Ts{Is}...); }

template <typename ... Ts>
auto make_derives_tuple ()
 { return make_helper<Ts...>(std::index_sequence_for<Ts...>{}); }

int main()
 {
   auto t = make_derives_tuple<A, B, C, D>();

   using T0 = decltype(t);
   using T1 = std::tuple<A, B, C, D>;

   static_assert( std::is_same<T0, T1>::value, "!" );
 }