Как наследоваться от списка типов, а затем вызывать член из списка унаследованных членов?

У меня есть набор классов, которые имеют следующую структуру:

class U
{
public:
    explicit U(int) { ... }
    U() {...}
    Init(int) {...}
};

Мне нужно иметь возможность составить 1 или несколько из этих классов в класс X. Псевдокод:

template<class TypeSequence>
class X that derives publicly from all the classes in TypeSequence
{
    X(int): all bases are initialized with the integer passed 
    {}
    //if the above constructor is impossible, then the following will do as well:
    X(int)
    {
        Call Init on all bases and pass the given int to them.
    }
};

Я думаю, что мне нужно много mpl, но я не очень хорош в этом. Выполнимо ли то, что я пытаюсь сделать? Пример кода был бы отличным.

МОЯ ОШИБКА: Забыл упомянуть, что не могу использовать функции C++11. Я ищу решение MPL.


person Armen Tsirunyan    schedule 08.09.2011    source источник
comment
+1 Хороший вопрос. Кстати, вы слышали о миксине? Может быть, он может быть применим здесь, или его вариант?   -  person Nawaz    schedule 08.09.2011
comment
Я делал именно это раньше с Boost.MPL, но у меня нет код удобен, и у меня нет времени, чтобы написать полный ответ прямо сейчас. Я вернусь к этому сегодня вечером, если никто не ответил к тому времени. В качестве подсказки я припоминаю создание специального миксина, который принимает два итератора boost::mpl::vector<> в качестве аргументов шаблона.   -  person ildjarn    schedule 08.09.2011
comment
Как U связан с TypeSequence?   -  person Captain Giraffe    schedule 08.09.2011
comment
@Nawaz: я не думаю, что миксин применим. Мне не нужна информация о производном классе в классах U. Мне нужно что-то вроде mpl::inherit_linearly, я просто не могу понять синтаксис. Также я понятия не имею, как я могу инициализировать базы или вызвать на них Init.   -  person Armen Tsirunyan    schedule 08.09.2011
comment
Определенно нуждается в функции вариативного шаблона C++0x.   -  person Frigo    schedule 08.09.2011
comment
@Captain: U - это не один класс. Таких классов, как U, очень много. TypeSequence — это последовательность таких типов.   -  person Armen Tsirunyan    schedule 08.09.2011
comment
@ildjarn: С нетерпением жду :)   -  person Armen Tsirunyan    schedule 08.09.2011
comment
@Frigo: я почти уверен, что MPL подойдет   -  person Armen Tsirunyan    schedule 08.09.2011


Ответы (4)


Что ж, Boost.MPL содержит метафункции inherit и inherit_linearly, вы можете комбинировать их с for_each, чтобы получить второй вариант (с функциями инициализации). Или используя только boost::mpl::fold и пользовательские метафункции:

struct Null_IntConstructor
{
  Null_IntConstructor(int) { }
};

struct InheritFrom_IntConstructor_Folder
{
  template<typename T1, typename T2>
  struct apply
  {
    struct type : T1, T2
    {
      type(int x) : T1(x), T2(x) { }
    };
  };
};

template<typename Bases>
struct InheritFrom_IntConstructor 
  : boost::mpl::fold<Bases, 
                     Null_IntConstructor,
                     InheritFrom_IntConstructor_Folder>::type
{
  InheritFrom_IntConstructor(int x) 
    : boost::mpl::fold<Bases, 
                       Null_IntConstructor,
                       InheritFrom_IntConstructor_Folder>::type(x) 
  { }
};

Пример использования:

#include <iostream>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/vector.hpp>

struct A
{
  A(int x) { std::cout << "A::A " << x << std::endl; }
};

struct B
{
  B(int x) { std::cout << "B::B " << x << std::endl; }
};

struct C
{
  C(int x) { std::cout << "C::C " << x << std::endl; }
};

int main()
{
  InheritFrom_IntConstructor< boost::mpl::vector<A, B, C> >(1);
}

Метафункция InheritFrom_IntConstructor может обобщаться, чтобы принимать произвольный тип в качестве параметра конструктора, и я не уверен, можно ли обобщать, чтобы принимать произвольное количество аргументов.

person Begemoth    schedule 08.09.2011
comment
@Begeoth: работает отлично. Однако мне нужно разобраться, что именно делает fold, но большое спасибо! - person Armen Tsirunyan; 08.09.2011
comment
@Armen: mpl::fold делает почти то же самое, что и я в своем решении. - person Nawaz; 08.09.2011

Что-то вроде этого?

template <typename ...BaseClasses>
class Aggregator : public BaseClasses...
{
public:
    Aggregator(int i) : BaseClasses(i)...
    {}

};

Пример использования:

Aggregator<U, V, W> a(10);
Aggregator<U, V> b(15);
Aggregator<W> c(20);

Примечание: он использует вариативные шаблоны, поэтому требуется C++11.

person Matteo Italia    schedule 08.09.2011
comment
+1: Это так чисто и просто. Спасибо. К сожалению, К сожалению, я не могу использовать шаблоны с переменным числом аргументов :( - person Armen Tsirunyan; 08.09.2011
comment
BaseClasses(i)... Это работает? § 14.5.3/5, кажется, читается так! Аккуратный! - person Mooing Duck; 08.09.2011
comment
Хороший пример выразительности C++11. Я хочу обобщить исходный вопрос на произвольное количество аргументов конструктора произвольных типов. - person Begemoth; 08.09.2011
comment
@Mooing Duck: на самом деле для меня это совершенно новый аргумент, я действительно не проверял стандарт, g ++ принял его и предположил, что он правильный. :п - person Matteo Italia; 08.09.2011

Я не использую Boost и не уверен, насколько мое решение ближе к тому, что вам нужно. Но все же выкладываю:

template<typename typeseq>
struct X : typeseq::head, X<typename typeseq::tail>
{
   typedef typename typeseq::head base;
   typedef X<typename typeseq::tail> recursebase;
   X(int i) : base(i), recursebase(i) {}
   void init(int i) 
   {
       base::init(i);
       recursebase::init(i);
   }
};

template<>
struct X<null_type> 
{
   X(int i) {}
   void init(int i)  { } 
};

И затем, тестирующий код:

typedef typelist<S,typelist<U>> typeseq;
X<typeseq> x(10);
x.init(100);

Онлайн-демонстрация: http://ideone.com/e6tuM

person Nawaz    schedule 08.09.2011
comment
Когда я увидел ответ Бегемота, это тоже пришло мне в голову, и я собирался опубликовать его. Вы были быстрее, хотя: D Гораздо лучший ответ, чем мои оригиналы. - person Mooing Duck; 08.09.2011

Что-то вроде этого должно работать:

template<class typeOne>
class X1 : public typeOne
{
    X(int b): typeOne(b)
    {}
};
template<class typeOne, class typeTwo>
class X2 : public typeOne, public typeTwo
{
    X(int b): typeOne(b), typeTwo(b)
    {}
};
template<class typeOne, class typeTwo, class TypeThree>
class X3 : public typeOne, public typeTwo, public typeThree
{
    X(int b): typeOne(b), typeTwo(b), typeThree(b)
    {}
};

или, если вы готовы тратить несколько байтов на объект, вы можете использовать заполнитель и сделать его только большим. Это должно привести к потере не более одного байта на неиспользуемый базовый тип для каждого экземпляра.

template<int>
class PlaceHolder { PlaceHolder(int){} };

template<
         class typeOne, 
         class typeTwo=PlaceHolder<2>, 
         class TypeThree=PlaceHolder<3>,
         class TypeFour=PlaceHolder<4>,
         class TypeFive=PlaceHolder<5>
        >
class X : 
         public typeOne, 
         public typeTwo, 
         public typeThree,
         public typeFour,
         public typeFive
{
    X(int b)
    : typeOne(b), 
    typeTwo(b), 
    typeThree(b),
    typeFour(b),
    typeFive(b)
    {}

    X(const X& b)
    : typeOne(b), 
    typeTwo(b), 
    typeThree(b),
    typeFour(b),
    typeFive(b)
    {}

    X& operator=(const X& b) {
        typeOne::operator=(b);
        typeTwo::operator=(b);
        typeThree::operator=(b);
        typeFour::operator=(b);
        typeFive::operator=(b);}
        return *this;
    }
};
person Mooing Duck    schedule 08.09.2011
comment
У вас не может быть одного и того же шаблона с разными номерами аргументов шаблона. - person Armen Tsirunyan; 08.09.2011
comment
хорошо, изменили имена шаблонов и добавили версию, которая работает только с одним именем, но может занимать место впустую. - person Mooing Duck; 08.09.2011
comment
Честно говоря, мне не нравится ваше решение, но я поддерживаю его, потому что вы потратили время, пытаясь мне помочь. Спасибо - person Armen Tsirunyan; 08.09.2011
comment
Честно говоря, мне тоже не нравится мое решение. :D - person Mooing Duck; 08.09.2011