C++ void_t模板详解 | SFINAE与类型萃取

C++ void_t:优雅的类型萃取工具 #

引言 #

void_t 是 C++17 引入的一个强大的模板工具,它看似简单,但在模板元编程中发挥着重要作用。

基本原理 #

void_t 的定义非常简单:

template<class...> using void_t = void;

它的强大之处在于与SFINAE(Substitution Failure Is Not An Error)结合使用时的表达能力。

实际应用示例 #

1. 检测类型成员 #

template <class, class = std::void_t<>>
struct has_type : std::false_type {};

template <class T>
struct has_type<T, std::void_t<typename T::type>> : std::true_type {};

2. 检测成员变量 #

template <class, class = std::void_t<>>
struct has_a_member : std::false_type {};

template <class T>
struct has_a_member<T, std::void_t<decltype(std::declval<T>().a)>> : std::true_type {};

3. 检测迭代器支持 #

template <typename, typename = void>
constexpr bool is_iterable{};

template <typename T>
constexpr bool is_iterable<T, std::void_t<
    decltype(std::declval<T>().begin()),
    decltype(std::declval<T>().end())>> = true;

4. 检测成员函数 #

template <class T, class = void>
struct has_hello_func : std::false_type {};

template <class T>
struct has_hello_func<T, std::void_t<decltype(std::declval<T>().hello())>> 
    : std::true_type {};

使用示例 #

struct HasType {  
    typedef int type;
};
struct NHasType {  
    int hello;
};

struct Hasa {  
    int a;
};
struct NHasa {  
    int b;
};

struct HasHello {  
    void hello();
};
struct NoHasHello {};

int main() {
    std::cout << has_type<HasType>::value << '\n';   // 1
    std::cout << has_type<NHasType>::value << '\n';  // 0

    std::cout << has_a_member<Hasa>::value << '\n';   // 1
    std::cout << has_a_member<NHasa>::value << '\n';  // 0

    std::cout << has_hello_func<HasHello>::value << '\n';    // 1
    std::cout << has_hello_func<NoHasHello>::value << '\n';  // 0

    std::cout << is_iterable<std::vector<double>> << '\n';  // 1
    std::cout << is_iterable<double> << '\n';               // 0
}

它的原理其实就是利用 SFINAE 和模板优先找特化去匹配的特性,估计大家应该看示例代码就能明白。