создает кортеж, содержащий различные элементы класса накопителя, конструктор которого получил тип int, определяемый его индексом в кортеже - PullRequest
0 голосов
/ 13 января 2019

У меня есть базовый класс, конструктор которого получает тип 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 голосов
/ 13 января 2019

Я не вижу элегантного способа перебора простых классов, таких как 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, "!" );
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...