2017-08-04 57 views
4

当我第一次学会了如何在一个类检查特定的签名,我学会了使用std::void_t,写一些像这样的代码:为了检查一个类是否有一个具有特定签名的方法,是否需要`void_t`?

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{}; 

而这个代码片段将检查如果一个类有一个名为方法“print()”。它运作良好。

但是,当我试图删除std::void_t,它仍然工作。

的代码看起来是这样的:

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

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

所以我很困惑,如果“std::void_t”是必要的检查,如果一个类与特定签名的方法?或者那只是一个巧合?

回答

10

This question详细解释了void_t(或称为检测成语)是如何工作的。关键在于只有在第二个模板参数的类型为void时才会考虑专业化。

在这种情况下,恰巧你的print()方法返回void,所以decltype(declval<T>().print())也是无效的。但是如果你的print()返回了其他的东西,比如说bool,那么专业化不匹配,不会被使用。

+0

谢谢你,当我在等待这个问题的答案,我改变了打印的返回类型为int。正如你所说,它失败了。非常感谢。 – Kidsunbo

+0

那真是巧合! – alfC

4

“void_t”是检查一个类是否有特定签名的方法所必需的吗?

+1为Tristan Brinde答案;但我的答案是:std::void_t帮助,但(在你的情况)是没有必要的。

可以使用逗号特技

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

下面是一个编译(在C++ 11太; std::void_t只能从C++ 17)完整的例子

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, "!!"); 
} 
0

所以我很困惑,如果需要“std::void_t

要我不完全清楚你的意思。如果您的意思是由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

相关问题