Наследование от списка шаблонных классов, когда предоставляется список аргументов шаблона - PullRequest
4 голосов
/ 26 февраля 2010

Я пытаюсь написать некоторый код метапрограммирования, такой:

  • Наследование от некоторого класса foo<c1, c2, c3, ...> приводит к наследованию от key<c1>, key<c2>, key<c3>, ...
  • Самый простой подход не совсем работает, потому что вы не можете наследовать от одного и того же пустого класса более одного раза.
  • Работа с частью "..." не очень привлекательна (так как это копия-паста), но работает.

Хорошо, вот попытка:

template<char c0, typename THEN, typename ELSE>
struct char_if
{
    typename THEN type;
};
template<typename THEN, typename ELSE>
struct char_if<0, THEN, ELSE>
{
    typename ELSE type;
};
class emptyClass {};


template<char c> class key
{
    char getKey(){return c;}
};

template<char c0, char c1, char c2, char c3, char c4>
class inheritFromAll
{
    typename char_if<c0, key<c0>, emptyClass>::type valid;

    class inherit
        : valid
        , inheritFromAll<c1, c2, c3, c4, 0>::inherit
    {};
};

template<char c1, char c2, char c3, char c4>
class inheritFromAll<0, c1, c2, c3, c4>
{
    class inherit {};
};

template<char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0, char c4 = 0>
class whatINeedToDo
    : public inheritFromAll<c0, c1, c2, c3, c4>::inherit
{
    bool success(){return true;}

};

int main() 
{
    whatINeedToDo<'A', 'B', 'c', 'D'> experiment;
    return 0;
}

Первоначально, хотя я мог использовать Boost :: Mpl, чтобы сделать это, но я, честно говоря, не мог понять, как; Я не мог понять, как вы обойдете list<...>, не всегда явно зная часть ....

Просто делаю:

template<> class key<0> {};

не работает, потому что если у меня есть более одного 0 параметра, я пытаюсь наследовать одно и то же дважды. (Если вы можете придумать обходной путь для этого, это также сработает).

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

Есть идеи?

Редактировать: у меня плохое решение. Я все еще хотел бы решение метапрограммирования, для обучения, но плохое решение - это:

template<char c1, char c2, char c3> class inheritFromMany
    : public key<c1>
    , public key<c2>
    , public key<c3>
{

};
template<char c1, char c2> class inheritFromMany<c1, c2, 0>
    : key<c1>
    , key<c2>
    {

    };

Edit2: Гав, но я забыл часть. Мне нужно передать переменную конструктору '' ключа '' - она ​​одинакова во всех случаях, но это необходимо.

Edit3: адресация комментариев:

  • Я не ожидаю, что пользователь отправит один и тот же символ более одного раза. Если бы они это сделали, я бы только хотел наследовать от этого ключа один раз - я имею в виду, я думаю, я не упомянул об этом, потому что вы не можете этого сделать? Вот почему другие, более простые решения не работают?
  • Фактически это означает, что ключ является оболочкой для поведения сигнал / слот (канал). Канал хранит список обратных вызовов, который на самом деле составляет всего virtual key<ch>::callback. Таким образом, наследование от ключа дает вам доступ к каналу этого ключа, позволяет (или заставляет) предоставить обратный вызов. keyInput<ch1, ch2, ch3,...> является тогда оберткой для этого, так что вам не нужно key<ch1>, key<ch2>, key<ch3>

1 Ответ

3 голосов
/ 26 февраля 2010

Если вы не скажете, чего вы на самом деле хотите достичь, это в основном академическое упражнение ... но вот один из способов, как использовать MPL для линейного наследования:

template<class T> struct key {
    enum { value = T::value };
    char getKey() { return value; }
};

template<class Values> struct derivator 
    : mpl::inherit_linearly<
          Values
        , mpl::inherit< mpl::_1, key<mpl::_2> >
        >::type
{};

// usage:    
typedef mpl::vector_c<char, 1,2,3> values;
typedef derivator<values> generated;

// or:
derivator< mpl::vector_c<char, 1,2,3> > derived;

Может быть, вы сможете уточнить на этой основе, что вам нужно.

Мне нужно передать переменную конструктору '' ключа '' - она ​​одинакова во всех случаях, но это необходимо.

Вы хотите сказать, что хотите передать параметр через цепочку наследования всем конструкторам? Затем взгляните на решения этого вопроса .


Что касается исключения mpl::vector_c в видимом интерфейсе, вы можете использовать свой предыдущий подход и построить его внутренне, вставив в него только значения, не равные нулю:

template<char c, class S> struct push_char {
    typedef typename mpl::push_front<S, mpl::char_<c> >::type type;
};

template<class S> struct push_char<0, S> {
    typedef S type; // don't insert if char is 0
};

template<char c1=0, char c2=0, char c3=0>
struct char_vector { 
    // build the vector_c
    typedef 
        typename push_char<c1
      , typename push_char<c2
      , typename push_char<c3
      , mpl::vector_c<char> 
      >::type>::type>::type
    type; 
};

template<char c1=0, char c2=0, char c3=0> 
struct derivator 
    : mpl::inherit_linearly<
          typename char_vector<c1,c2,c3>::type
        , mpl::inherit< mpl::_1, key<mpl::_2> >
        >::type
{};
...