检测表达式是否有效
可以检测是否可以在类型上调用操作符或函数。要测试一个类是否具有 std::hash
的重载,可以执行以下操作:
#include <functional> // for std::hash
#include <type_traits> // for std::false_type and std::true_type
#include <utility> // for std::declval
template<class, class = void>
struct has_hash
: std::false_type
{};
template<class T>
struct has_hash<T, decltype(std::hash<T>()(std::declval<T>()), void())>
: std::true_type
{};
Version >= C++ 17
从 C++ 17 开始,std::void_t
可用于简化这种类型的构造
#include <functional> // for std::hash
#include <type_traits> // for std::false_type, std::true_type, std::void_t
#include <utility> // for std::declval
template<class, class = std::void_t<> >
struct has_hash
: std::false_type
{};
template<class T>
struct has_hash<T, std::void_t< decltype(std::hash<T>()(std::declval<T>())) > >
: std::true_type
{};
其中 std::void_t
定义为:
template< class... > using void_t = void;
为了检测是否定义了运算符,例如 operator<
,语法几乎相同:
template<class, class = void>
struct has_less_than
: std::false_type
{};
template<class T>
struct has_less_than<T, decltype(std::declval<T>() < std::declval<T>(), void())>
: std::true_type
{};
如果 T
对 std::hash
有超载,这些可用于使用 std::unordered_map<T>
,但是否则尝试使用 std::map<T>
:
template <class K, class V>
using hash_invariant_map = std::conditional_t<
has_hash<K>::value,
std::unordered_map<K, V>,
std::map<K,V>>;