在模板类中匹配CRTP

时间:2011-10-23 23:31:54

标签: c++ templates crtp

最近我一直在玩模板并偶然发现以下问题。我正在实现这样的CRTP模式:

template<typename derived_t>
struct protocol_object
{
    ...
};

struct data_object : public protocol_object<data_object>
{
    ...
};

我现在想在成员模板函数中匹配class protocol_object的实例,同时仍然接受非CRTP类型:

struct consumer_impl
{
    template<typename derived_t>
    void match(protocol_object<derived_t> &value)
    {
       std::cout << "protocol_class";
    };

    template<typename T>
    void match(T &value)
    {
       std::cout << "any other type";
    };
}

不幸的是,只有第二个版本被调用。显然match(protocol_object<derived_t> &value)不会被视为或拒绝使用更为通用的格式match(T &value)

data_object object;
double value;
consumer_impl consumer;

consumer.match(value);  // yields "any other type" OK
consumer.match(object); // also yields "any other type" but want "protocol_class"

有没有办法解决这个问题?

感谢任何提示。 ·阿尔

3 个答案:

答案 0 :(得分:2)

这与CRTP无关。这是以下的一般情况:

  • 设计模板函数,以便所有派生类都使用特定的特化。

问题是T& valueDerived&完全匹配,而Base&是不精确的匹配。因此,我们将使一般形式更糟糕:

struct conversion_required { conversion_required(int) {} };

template<typename derived_t>
void match_impl(protocol_object<derived_t> &value, int)
{
   std::cout << "protocol_class";
};

template<typename T>
void match_impl(T &value, conversion_required)
{
   std::cout << "any other type";
};

template<typename T>
void match(T& value)
{
    return match_impl(value, 0);
}

现在需要转发的专业化比一般模板更好,需要用户定义的转换。

答案 1 :(得分:0)

重载决策是基于静态类型执行的,因为它是编译时编译器的决定。试试这个:

consumer.match(static_cast<protocol_object<data_object>&>(object));

答案 2 :(得分:0)

第二个函数是更好的匹配,因为它不需要转换,而第一个函数需要派生到基础的转换。

你可以使用boost来克服这个问题:

template <class T>
void
match (typename boost::enable_if_c
             <boost::is_base_of<protocol_object<T>,T>::value, T>::type& t)
{
    std::cout << "protocol_class";
}

template <class T>
void
match (typename boost::disable_if_c
             <boost::is_base_of<protocol_object<T>,T>::value, T>::type& t)
{
    std::cout << "any other type";
}

这适用于从T派生的所有课程protocol_object<T>,但不适用于protocol_object<T>本身。您可以为它添加另一个重载(基本上,重用您的第一个match函数),或修改enable_if中的条件,使其与protocol_object<T>匹配。