在 C++11 中,我发现的最短最通用的解决方案是这个:
#include <type_traits>
template<class T, class = decltype(std::declval<T>() < std::declval<T>() )>
std::true_type supports_less_than_test(const T&);
std::false_type supports_less_than_test(...);
template<class T> using supports_less_than = decltype(supports_less_than_test(std::declval<T>()));
#include<iostream>
struct random_type{};
int main(){
std::cout << supports_less_than<double>::value << std::endl; // prints '1'
std::cout << supports_less_than<int>::value << std::endl; // prints '1'
std::cout << supports_less_than<random_type>::value << std::endl; // prints '0'
}
适用于g++ 4.8.1
和clang++ 3.3
任意运算符的更通用解决方案(2014 年更新)
有一个更通用的解决方案利用了这样一个事实,即所有内置运算符也可以通过 STD 运算符包装器访问(并且可能是专门的),例如std::less
(binary) 或std::negate
(unary)。
template<class F, class... T, typename = decltype(std::declval<F>()(std::declval<T>()...))>
std::true_type supports_test(const F&, const T&...);
std::false_type supports_test(...);
template<class> struct supports;
template<class F, class... T> struct supports<F(T...)>
: decltype(supports_test(std::declval<F>(), std::declval<T>()...)){};
这可以以非常通用的方式使用,尤其是在 C++14 中,其中类型推导被延迟到运算符包装器调用(“透明运算符”)。
对于二元运算符,它可以用作:
#include<iostream>
struct random_type{};
int main(){
std::cout << supports<std::less<>(double, double)>::value << std::endl; // '1'
std::cout << supports<std::less<>(int, int)>::value << std::endl; // '1'
std::cout << supports<std::less<>(random_type, random_type)>::value << std::endl; // '0'
}
对于一元运算符:
#include<iostream>
struct random_type{};
int main(){
std::cout << supports<std::negate<>(double)>::value << std::endl; // '1'
std::cout << supports<std::negate<>(int)>::value << std::endl; // '1'
std::cout << supports<std::negate<>(random_type)>::value << std::endl; // '0'
}
(使用 C++11 标准库稍微复杂一些,因为decltype(std::less<random_type>()(...))
即使没有为 定义操作,实例化也不会失败random_type
,可以在 C++11 中手动实现透明操作符,这是 C++14 中的标准)
语法相当流畅。我希望在标准中采用这样的东西。
两个扩展:
1)它可以检测原始功能应用程序:
struct random_type{};
random_type fun(random_type x){return x;}
int main(){
std::cout << supports<decltype(&fun)(double)>::value << std::endl; // '0'
std::cout << supports<decltype(&fun)(int)>::value << std::endl; // '0'
std::cout << supports<decltype(&fun)(random_type)>::value << std::endl; // '1'
}
2)它可以额外检测结果是否可转换/可比较为某种类型,在这种情况下double < double
是支持的,但由于结果不是指定的,所以会返回编译时错误。
std::cout << supports<std::equal_to<>(std::result_of<std::less<>(double, double)>::type, random_type)>::value << std::endl; // '0'
注意:我只是尝试在http://melpon.org/wandbox/中使用 C++14 编译代码,但没有成功。我认为std::less<>
该实现(clang++ 3.5 c++14)中的透明运算符(如 )存在问题,因为当我less<>
使用自动推导实现我自己的时,它运行良好。