为何检测类重载+运算符时,C、D类型的判断结果为false?
为什么检测C和D的operator+重载返回false?
先看你写的检测模板:
template <typename T, typename = void> struct has_p_op : std::false_type {}; template <typename T> struct has_p_op<T, decltype(std::declval<T>() + std::declval<T>())> : std::true_type {};
核心问题是模板特化的第二个参数类型不匹配:
- 默认模板的第二个参数默认值是
void,只有当特化版本的第二个参数类型也是void时,才会触发特化,返回true_type。 - 对于B的
operator+,返回值是void,所以declval<B>() + declval<B>()的类型是void,特化的第二个参数刚好是void,匹配成功,结果为true。 - 对于C的
operator+,返回值是C,特化的第二个参数类型变成了C,和默认的void不匹配,所以不会触发特化,使用默认的false_type。 - 对于D的
operator+,返回值是D&,特化的第二个参数类型是D&,同样和void不匹配,结果自然是false。
解决方法
只需要让特化版本的第二个参数始终为void,不管operator+返回什么类型,有两种实现方式:
方式1:C++17及以上用std::void_t
需要引入<type_traits>头文件:
#include <type_traits> template <typename T, typename = void> struct has_p_op : std::false_type {}; template <typename T> struct has_p_op<T, std::void_t<decltype(std::declval<T>() + std::declval<T>())>> : std::true_type {};
方式2:兼容C++11及以上的void转换
对表达式做强制void转换,忽略返回值类型:
template <typename T, typename = void> struct has_p_op : std::false_type {}; template <typename T> struct has_p_op<T, decltype((void)(std::declval<T>() + std::declval<T>()))> : std::true_type {};
修改后,C和D的检测结果都会变为true,因为特化的第二个参数始终是void,和默认模板的参数匹配,触发特化逻辑。
内容的提问来源于stack exchange,提问作者deponovo
相关产品推荐
相关产品推荐

