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 和模板优先找特化去匹配的特性,估计大家应该看示例代码就能明白。