元编程,试图避免许多专业化

时间:2016-09-15 17:11:23

标签: c++ templates metaprogramming traits typetraits

我正致力于为旧程序添加新内容,旧程序在任何地方都使用元编程。我仍然在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 > >
  5. 两种附肢类型:
    SmallAppendage
    BigAppendage

    每条消息的标题中都有条件变量,具体取决于它 getValue()应该从消息中获取字段或返回零。如果类型没有附属物,则该字段可以在消息本身中, 或者在附件中,或者如果消息附带附件,则同时在消息本身。

    对于没有附属物的消息,我需要类似Base类的东西;对于带有附属物的消息,我需要扩展 类似的东西:

    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;
        }
    };
    

    编辑:我的特质现在已编译。是否有可能使这个工作:

    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;
        }
    };
    

    编辑:现在它的参数1的类型/值不匹配

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

    期望一个类模板得到..类模板!,但它不会以某种方式识别。

    编辑: 我解决了这个错误,原因是:

      

    与普通(非模板)类一样,类模板具有注入类名(第9节)。 inject-name-name可以使用或不使用template-argument-list。如果在没有template-argument-list的情况下使用它,它等同于inject-name-name,后跟&lt;&gt;中包含的类模板的template-parameters。当它与template-argument-list一起使用时,它引用指定的类模板特化,可以是当前的特化或其他特化。

    正确的代码:

    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;
        }
    };
    

1 个答案:

答案 0 :(得分: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);
    ....
}