Is `void_t` necessary to check if a class has a method with a specific signature?

时间:2017-08-04 12:15:45

标签: c++ c++11 templates template-meta-programming c++17

When I first learned how to check a specific signature in a class, I was taught to use std::void_t and write some code like this:

template<typename T, typename =void>
class HAS:public false_type{};

template<typename T>
class HAS<T,void_t<decltype(declval<T>().print())>>:public true_type{};

And this snippet of code will check if a class has the method named "print()". It works well.

But when I tried to remove the std::void_t, it still worked.

The code looks like this:

template<typename T, typename = void>
class HAS:public false_type{};

template<typename T>
class HAS<T,decltype(declval<T>().print())>:public true_type{};

So I am confused if "std::void_t" is necessary to check if a class has a method with a specific signature? Or that's only a coincidence?

3 个答案:

答案 0 :(得分:10)

This question explains in detail how void_t (otherwise known as the detection idiom) works. The key point is that the specialisation will only be considered if the type of the second template parameter evaluates to void.

In this case, it just so happens that your print() method returns void, so decltype(declval<T>().print()) is also void. But if your print() returned something else, say bool, then the specialisation would not match and would not be used.

答案 1 :(得分:4)

"void_t" is necessary to check if a class has a method with a specific signature?

+1 for the Tristan Brinde answer; but my answer is: std::void_t helps but (in your case) isn't necessary.

You can use the comma trick

decltype(std::declval<T>().print(), void())

The following is a compiling (in C++11 too; std::void_t is available only from C++17) full example

struct foo
 { };

struct bar
 { int print () const { return 0; } };

template <typename T, typename = void>
class HAS
   : public std::false_type
 { };

template <typename T>
class HAS<T, decltype(std::declval<T>().print(), void())>
   : public std::true_type
 { };

int main ()
 {
   static_assert( HAS<foo>::value == false, "!" );
   static_assert( HAS<bar>::value == true,  "!!" );
 }

答案 2 :(得分:0)

  

所以我很困惑,如果&#34; std::void_t&#34;是必要的

对我来说,你的意思并不完全清楚。如果你的意思是void_t使用的SFINAE表达式,那么答案是。如果您的意思是否需要明确提及void_t,那么答案就是

例如,在C ++ 17中,您可以使用is_detected方法,该方法也是std::experimental的一部分。对于其他方法,请参阅其他答案。

#include <experimental/type_traits>

template < typename T >
using print_t = decltype(std::declval<T>().print());

template < typename T >
using has_print = std::experimental::is_detected< print_t, T >;

struct A {};

struct B { void print() {} };

int main()
{
  static_assert( has_print<A>::value == false );
  static_assert( has_print<B>::value == true  );
}

Live example