在模板运算符重载中键入冲突

时间:2012-11-24 16:12:09

标签: c++ c++11

对不起,这听起来像是一个常见的问题,就我看来,我无法找到问题的答案。最近的帖子是这一个:Template Specialization for basic POD only

假设我有一个类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类型,这不是重点。如果我这样做,问题是如果它是A,我无法知道U中包含什么底层模板类型。

如果我的问题不够明确,请告诉我,并提前致谢! :)

编辑:HTML过滤器消除了模板规范,在我的最后一句“U如果它是A<T>”中。简而言之,我说T是隐藏的。

2 个答案:

答案 0 :(得分: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来控制重载集的示例。)

答案 1 :(得分: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分辨率更差。