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?
答案 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 );
}