5

很抱歉,这听起来像是一个常见问题,就我所看到的而言,我找不到问题的答案。最接近的帖子是:Template Specialization for basic POD only

假设我有一个 class template <class T> class A {...};,我想重载 operator+ 作为内部二元运算符(A 类型的两个对象)和混合二元运算符(A 类型和数字 POD 类型的对象)。

理想情况下,我想写的是:

#include <type_traits>
using namespace std;

// Declare/fine template
template <class T> class A {...};

// Internal binary operator
template < class T, class U >
    A< typename common_type<T,U>::type >
operator+ ( const A<T> &a, const A<U> &a ) { ... }

// Mixed binary operator
template < class T, class U >
    A< typename common_type<T,U>::type >
operator+ ( const A<T> &a, const U &b ) { ... }

但似乎第二个定义与第一个定义相冲突。使用第二个定义,我知道如何确保 U 是数字 POD 类型,这不是重点。如果我这样做,问题是我无法知道 U 中包含的底层模板类型(如果它是某个 A)。

如果我的问题不够清楚,请告诉我,并提前感谢!:)

编辑:模板规范被 HTML 过滤器清除,在我的最后一句“U if it is some A<T>”中。简而言之,我是说 T 是隐藏的。

4

2 回答 2

2

您可以使用一些辅助特征使其工作,以区分专业化和A更一般的类型:

#include <type_traits>


// "A" template    

template <typename> class A {};


// Traits for "A-ness":

template <typename> struct is_a : std::false_type { };
template <typename T> struct is_a<A<T>> : std::true_type { };


// Operators:

template <class T, class U>
A<typename std::common_type<T, U>::type>
operator+(const A<T> & a, const A<U> & b);

template <class T, class U,
          typename = typename std::enable_if<!is_a<U>::value>::type>
A<typename std::common_type<T, U>::type>
operator+(const A<T> & a, const U & b);

这会立即从可行集中排除第二个重载,因此当只需要第一个重载时,永远不会出现确定第二个重载的返回类型的问题。

(这是使用enable_if默认模板参数来控制重载集的示例。)

于 2012-11-24T16:56:16.210 回答
1

你可以写一个对 SFINAE 友好的东西common_type——我个人认为特质应该几乎总是 SFINAE。以机智:

// Black hole metafunction that eats everything
template<typename...> struct void_ { using type = void; };

template<typename... T>
using Void = typename void_<T...>::type;

// Due to std::common_type being variadic we need to
// pass a variadic pack around
template<typename... T> struct list {};

// Actually defined, but with no member types for SFINAE purposes
template<typename Sequence, typename Sfinae = void>
struct common_type_impl {};

template<typename... T>
struct common_type_impl<list<T...>, Void<typename std::common_type<T...>::type>>
: std::common_type<T...> {};

template<typename... T> struct common_type: common_type_impl<list<T...>> {};

现在,当两者之间没有公共类型时,A<T>重载U将从候选列表中删除,而不是大声抱怨。

也可以std::common_type完全替换,因为它计算的结果有其自身的问题,如DR 2141中所述。我不会概述替代方案,因为不清楚什么是更好的解决方案,特别是我认为提议的 DR 解决方案更糟糕。

于 2012-11-25T09:40:34.130 回答