【C++】C++17 std::void_t的用法

模板元编程中,用此元函数检测 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
发布了423 篇原创文章 · 获赞 14 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/LU_ZHAO/article/details/105480473