2016-09-15 11 views
1

Я работаю над добавлением нового контента в старую программу, которая везде использует метапрограммирование. Я все еще на C++ 03 и повышу. Так вот проблема: я сделал шаблон функции, что я не хочу, чтобы специализироваться из-за различий только в четырех вызовов функции, чтобы получить конкретные значения:Метапрограммирование, пытаясь избежать многих специализаций

template < typename Message > 
void function(const Message & message) 
{ 
    .... 
    int value = getHelper...getValue(); 
    .... 
} 

Есть много различных типов сообщений:

  1. MessageA: public BaseForA<MessageA>
  2. MessageB: public BaseForB<MessageB>
  3. template < typename Appendage > MessageAWithAppendage <Appendage>: public BaseForA< MessageA <Appendage> >
  4. template < typename Appendage > MessageB: public BaseForB<MessageB>: public BaseForB< MessageB <Appendage> >

И два придатков тип:
SmallAppendage
BigAppendage

Существует переменное условие в заголовке каждого сообщения, в зависимости от этого getValue() должен получить поле из сообщения или возвращать ноль. Это поле может быть в самом сообщении, если тип без придатка, или в придатке ИЛИ в то же время в самом сообщении, если сообщение с придатком.

мне нужно что-то вроде класса Base для сообщений без придатков и Extended для сообщений с придатком что-то вроде:

template < typename Message > 
class Helper 
{ 
public: 
    virtual int getValue(const Message & msg) 
    { 
     if(..) 
     { 
      return msg.value; 
     } 
     ... 
    } 
}; 

template< template <class> class Message, typename Appendage > 
class ExtendedHelper : public Helper < Message <Appendage> > 
{ 
public: 
    virtual int getValue(const Message<Appendage> & msg) 
    { 
     int value = Helper::getValue(msg); 
     if(value) 
     { 
      return value; 
     } 
     return msg.appendage.getValue(); 
    } 
}; 

После того, что я думал, что-то, как это будет работать, но это не так:

template < class Type > 
struct AppendageTraits 
{ 
    enum { appendageIncluded = false }; 
}; 

template < class Appendage > 
struct AppendageTraits < MessageAWithAppendage <Appendage> > 
{ 
    enum { appendageIncluded = true }; 
}; 

template < class Appendage > 
struct AppendageTraits < MessageBWithAppendage <Appendage> > 
{ 
    enum { appendageIncluded = true }; 
}; 

template< typename Message , bool > 
struct GetHelper 
{ 
    Helper<Message> * operator()() 
    { 
     static Helper<Message> helper; 
     return &helper; 
    } 
}; 

EDIT: Мои черты теперь компилируются. Можно ли сделать эту работу:

template < typename Appendage > 
struct GetHelper<MessageAWithAppendage <Appendage>, true> 
{ 
    Helper< MessageAWithAppendage <Appendage> > * operator()() 
    { 
     static Helper< MessageAWithAppendage <Appendage>, Appendage > helper; 
     return &helper; 
    } 
}; 

template < typename Appendage > 
struct GetHelper<MessageBWithAppendage <Appendage>, true> 
{ 
    Helper< MessageBWithAppendage <Appendage> > * operator()() 
    { 
     static ExtendedHelper< MessageBWithAppendage <Appendage>, Appendage > helper; 
     return &helper; 
    } 
}; 

EDIT: теперь имеют тип/несоответствие значений в параметре 1 для

static ExtendedHelper< MessageAWithAppendage <Appendage>, Appendage > helper; 

ожидается шаблон класса получил .. класс шаблон !, но это не как-то определенно.

EDIT: Я решил эту ошибку, из-за этого:

Как и обычные (не шаблон) классов, шаблоны классов имеют впрыскивается-имя-класса (пункт 9). Имя введенного класса может использоваться с или без шаблона-аргумента-списка. Когда он используется без списка шаблонов-аргументов, он эквивалентен имени введенного класса, за которым следуют шаблонные параметры шаблона класса, заключенного в <>. Когда он используется с шаблоном-аргументом-списком, он ссылается на указанную специализацию шаблона класса, которая может быть текущей специализацией или другой специализацией.

Правильный код:

template < typename Appendage > 
struct GetHelper<MessageAWithAppendage <Appendage>, true> 
{ 
    Helper< MessageAWithAppendage <Appendage> > * operator()() 
    { 
     static Helper< MessageAWithAppendage, Appendage > helper; 
     return &helper; 
    } 
}; 

template < typename Appendage > 
struct GetHelper<MessageBWithAppendage <Appendage>, true> 
{ 
    Helper< MessageBWithAppendage <Appendage> > * operator()() 
    { 
     static ExtendedHelper< MessageBWithAppendage, Appendage > helper; 
     return &helper; 
    } 
}; 

ответ

2

Моя голова болит после прочтения всего этого, но если это только одна операция, которую вы хотите специализироваться, почему бы не сделать функтор с (возможно, шаблонных) перегрузках (по существу статический посетитель):

struct ValueGetter 
{ 
    int operator()(const MessageA& ma) const { 
    return ma.whatever_we_need_to_do(); 
    } 
    int operator()(const MessageB& mb) const { 
    return mb.whatever_we_need_to_do(); 
    } 
}; 

// this is now completely generic 
template < typename Message > 
void function(const Message & message) 
{ 
    .... 
    ValueGetter vg; 
    int value = vg(message); 
    .... 
} 
+0

Мне понадобится 4 таких хэпера с 6 специализациями, это на случай, если я не найду, как сделать его более компактным. – Ambrase

+0

Продолжайте находить общие вещи, чтобы специализироваться на. Некоторые из функций-членов могут быть самими шаблонами. Они создают новые геттеры. –

+0

Это то, чего я пытаюсь достичь. Взгляните на обновленный вопрос, если я найду, как заставить помощников работать моими качествами сейчас, все будет компактным. – Ambrase

 Смежные вопросы

  • Нет связанных вопросов^_^