模板元编程中,用此元函数检测 SFINAE 语境中的病式类型:
// 初等模板处理无嵌套 ::type 成员的类型:
template< class, class = std::void_t<> >
struct has_type_member : std::false_type { };
// 特化识别拥有嵌套 ::type 成员的类型:
template< class T >
struct has_type_member<T, std::void_t<typename T::type>> : std::true_type { };
它亦可用于检测表达式的合法性:
// 初等模板处理不支持前置自增的类型:
template< class, class = std::void_t<> >
struct has_pre_increment_member : std::false_type { };
// 特化识别支持前置自增的类型:
template< class T >
struct has_pre_increment_member<T,
std::void_t<decltype( ++std::declval<T&>() )>
> : std::true_type { };
C++11
void_t is a meta-function that maps any (number of) types to type void. The primary purpose of void_t is to facilitate writing of type traits.
std::void_t will be part of C++17, but until then, it is extremely straightforward to implement:
template <class...> using void_t = void;
Some compilers require a slightly different implementation:
template <class...>
struct make_void { using type = void; };
template <typename... T>
using void_t = typename make_void<T...>::type;
The primary application of void_t is writing type traits that check validity of a statement. For example, let’s check if a type has a member function foo() that takes no arguments:
template <class T, class=void>
struct has_foo : std::false_type {};
template <class T>
struct has_foo<T, void_t<decltype(std::declval<T&>().foo())>> : std::true_type {};
How does this work? When I try to instantiate has_foo::value, that will cause the compiler to try to look for the best specialization for has_foo<T, void>. We have two options: the primary, and this secondary one which involves having to instantiate that underlying expression:
- If T does have a member function foo(), then whatever type that returns gets converted to void, and the specialization is preferred to the primary based on the template partial ordering rules. So has_foo::value will be true
- If T doesn’t have such a member function (or it requires more than one argument), then substitution fails for the specialization and we only have the primary template to fallback on. Hence, has_foo::value is false.
如果有相同函数且参数类型相同就为true。
一个简单的例子:
template <class T, class=void>
struct has_foo : std::false_type {};
template <class T>
struct has_foo<T, std::void_t<decltype(std::declval<T&>().foo())>> : std::true_type {};
template <class T, class=void>
struct has_foo_int : std::false_type {};
template <class T>
struct has_foo_int<T, std::void_t<decltype(std::declval<T&>().foo(-1))>> : std::true_type {};
class A {};
class B { public:void foo(){} };
class C { void foo(){} };
class D { public:int foo(){return 1;} };
class E { public:int foo(int){return 2;} };
int main() {
std::cout << has_foo<A>::value << std::endl;//false
std::cout << has_foo<B>::value << std::endl;//true
std::cout << has_foo<C>::value << std::endl;//false
std::cout << has_foo<D>::value << std::endl;//true
std::cout << has_foo<E>::value << std::endl;//false
std::cout << has_foo_int<E>::value << std::endl;//true
return 0;
}
输出结果为:
:g++ -std=c++17 main.cc -o main
:./main
0
1
0
1
0
1