【问题标题】:creates a tuple contains different drive class elements whose constructor received an int type, determined by its index in the tuple创建一个包含不同驱动类元素的元组,其构造函数接收一个 int 类型,由其在元组中的索引确定
【发布时间】:2019-01-13 14:19:48
【问题描述】:

我有一个基类,它的构造函数接收一个名为 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));
}

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

【问题讨论】:

  • 即使只包含两个派生类,您能否提供实际的示例代码?上面的草图不是很清楚,因为它不符合 C++ 语法。

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


【解决方案1】:

我没有看到一种优雅的方式来遍历 Derived1、Derived2、Derived3 等简单的类。

但是,如果您可以模板化您的派生类,添加模板索引,如下所示或以类似方式

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

以下是一个完整的编译示例(我将派生类重命名为A、B、C 和D

#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, "!" );
 }

【讨论】:

  • 非常感谢!第二个真的很有帮助,我也从第一个例子中学习。
猜你喜欢
  • 2011-11-30
  • 2017-02-03
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 2020-09-18
  • 1970-01-01
  • 2021-08-24
  • 2017-11-08
相关资源
最近更新 更多