模板运算符重载中的类型冲突

Type conflict in template operator overload

本文关键字:类型 冲突 重载 运算符      更新时间:2023-10-16

很抱歉,这听起来像是一个常见的问题,据我所知,我找不到问题的答案。最接近的帖子是这样的:只针对基本POD的的模板专业化

假设我有一个类template <class T> class A {...};,我想重载运算符+作为内部二进制运算符(两个类型为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中包含的底层模板类型是什么

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

编辑:在我的最后一句话"U if it someA<T>"中,模板规范被HTML过滤器删除了。简而言之,我是说T是隐藏的。

您可以使用一个小的辅助特性来区分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来控制过载集的示例。)

你可以写一个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的拟议解决方案更糟。