匹配模板类中的CRTP

发布于 2024-12-11 15:31:19 字数 1032 浏览 0 评论 0原文

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

有办法解决这个问题吗?

感谢您的任何提示。 阿内

lately I've been toying around with templates and stumbled upon the following problem. I am implementing the CRTP pattern like this:

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

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

I now would like to match instances of class protocol_object in a member template function, while still accepting non CRTP-types:

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

Unfortunately only the second version is ever called. Apparently match(protocol_object<derived_t> &value) is not considered or rejected in favour of the more general form 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"

Is there a way out of this?

Thanks for any hints.
Arne

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南街女流氓 2024-12-18 15:31:19

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

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

This isn't related to CRTP. It's a general case of the following:

  • Design a template function, such that all derived classes use a particular specialization.

The issue is that T& value is an exact match for Derived&, while Base& is an inexact match. So we shall make the general form a worse match:

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

Now the specialization, requiring an upcast, is a better match than the general template, requiring a user-defined conversion.

千柳 2024-12-18 15:31:19

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

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

Overload resolution is performed based on the static type, since it is a compile-time compiler decision. Try this:

consumer.match(static_cast<protocol_object<data_object>&>(object));
回忆追雨的时光 2024-12-18 15:31:19

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

您可以使用 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,但不适用于 protocol_object本身。您可以为其添加另一个重载(基本上,重用您的第一个 match 函数),或者修改 enable_if 中的条件,使其匹配 protocol_object代码>也是。

The second function is a better match, as no conversion is required for it, whereas the first function requires a derived-to-base conversion.

You can use boost to overcome this:

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

This will work for all classes T derived from protocol_object<T>, but not for protocol_object<T> itself. You can add another overload for it (basically, reuse your first match function), or modify the condition in enable_if so that it matches protocol_object<T> too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文