匹配模板类中的CRTP

Matching CRTP in template class

本文关键字:CRTP      更新时间:2023-10-16

最近我一直在摆弄模板,偶然发现了以下问题。我像这样实现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"

有出路吗?

谢谢你的提示。阿恩

这与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);
}

现在,需要向上转换的专门化比需要用户定义转换的通用模板更匹配。

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

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

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

你可以使用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";
}

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