检测表达式是否有效

可以检测是否可以在类型上调用操作符或函数。要测试一个类是否具有 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
{};

如果 Tstd::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>>;