檢測表示式是否有效

可以檢測是否可以在型別上呼叫操作符或函式。要測試一個類是否具有 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>>;