使用`void_t`检查类是否具有带有特定签名的方法 [英] Using `void_t` to check if a class has a method with a specific signature
问题描述
参加 Walter E. Brown's元编程CppCon2014谈话,我开始怀疑是否可以在这种特殊情况下使用 void_t
来使代码更整洁,更具可读性。
但是我在考虑 void_t
时遇到了麻烦-到目前为止,我了解到 void_t
可以帮助我在编译时确定表达式是否有效。
示例:
template< class,class = void>
struct has_type_data_member:false_type {};
模板< T类
struct has_type_data_member< T,void_t< decltype(T :: data)> :true_type {};
如果 decltype(T :: type)
是一个有效的表达式, has_type_data_member< T>
将是一个真正的编译时常量。因此,我们确定 T
具有一个名为 data
的成员字段。
我想使用相同的方法来检查类型 T
是否具有带有特定名称和特定签名的方法。
假设我要检查 T
是否具有名为 getCount()
的方法,返回 int
。这就是我期望的工作((Ideone.com链接)):
template< class,class = void>
struct hasGetCount:false_type {};
模板< T类
结构hasGetCount< T,VoidT< decltype(T :: getCount)>
:std :: is_same< decltype(std :: declval< T>()。getCount()),int> :: type {};
不幸的是, static_assert
测试未通过。
我做错了什么?在这种情况下是否可以使用 void_t
?
奖金问题:
- 我还如何检查方法签名是否等于用户在原始实现中传递的签名?
-
我可以使用宏来定义此类辅助结构,如下所示:
DEFINE_METHOD_CHECKER(hasGetCount,getCount );
// ...
static_assert(hasGetCount< ClassWithGetCount> :: value == true,);
是否有可能避免定义
结构
然后再检查结构的值?我的意思是,是否可以使用宏编写类似这样的内容?示例:static_assert(CHECK_METHOD(ClassWithGetCount,getCount):: value == true,);
首先,命名为非静态成员函数的 id-expression 不能用作未求值的操作数(例如 decltype
的操作数)。此外,您应该检查整个函数调用表达式是否格式正确,而不仅仅是是否有一个名为 getCount
的成员:
template< class,class = void>
struct hasGetCount:false_type {};
模板< T类
结构hasGetCount< T,VoidT< decltype(std :: declval< T>()。getCount())>
:std :: is_same< decltype(std :: declval< T>()。getCount()),int> :: type {};
(使用 declval< T& c如果要检查是否可以在左值上调用
getCount()
。)
如果只检查 getCount
成员的存在,那么如果存在具有该名称但不可调用的成员(例如,数据成员),则会遇到硬错误。
尽管在这一点上,您也可以考虑使用
template< T类
结构hasGetCount< T,std :: enable_if_t< std :: is_same< decltype(std :: declval< T>()。getCount()),int> :: value>> :std :: true_type {};
而不是两次编写 decltype
。 / p>
At the moment, I'm using this method to check if a class has a method with a specific signature.
After attending Walter E. Brown's metaprogramming CppCon2014 talk, I started wondering if void_t
could be used in this particular situation to make the code cleaner and more readable.
However I'm having trouble thinking in terms of void_t
- so far I understand that void_t
can help me determine at compile-time whether or not an expression is valid.
Example:
template< class, class = void >
struct has_type_data_member : false_type { };
template< class T >
struct has_type_data_member<T, void_t<decltype(T::data)>> : true_type { };
If decltype(T::type)
is a valid expression, has_type_data_member<T>
will be a true compile-time constant. Therefore, we are sure that T
has a member field called data
.
I want to use the same approach to check if a type T
has a method with a particular name and a particular signature.
Let's say I want to check if T
has a method called getCount()
that returns int
. This is what I expected to work ((Ideone.com link)):
template< class, class = void >
struct hasGetCount : false_type { };
template< class T >
struct hasGetCount<T, VoidT<decltype(T::getCount)>>
: std::is_same<decltype(std::declval<T>().getCount()), int>::type { };
Unfortunately, the static_assert
tests do not pass.
What am I doing wrong? Is it possible to use void_t
in this situation?
Bonus questions:
- How can I also check if the method signature is equal to a signature the user passes as in the original implementation?
I can use macros to define these kind of helper structs like this:
DEFINE_METHOD_CHECKER(hasGetCount, getCount); // ... static_assert(hasGetCount<ClassWithGetCount>::value == true, "");
Is it possible to avoid having to define a
struct
first then check the struct's value? I mean, is it possible to use a macro to write something like this? Example:static_assert(CHECK_METHOD(ClassWithGetCount, getCount)::value == true, "");
First, an id-expression naming a nonstatic member function can't be used as an unevaluated operand (such as the operand of decltype
). Moreover, you should check for whether the entire function call expression is well formed, not just whether there is a member called getCount
:
template< class, class = void >
struct hasGetCount : false_type { };
template< class T >
struct hasGetCount<T, VoidT<decltype(std::declval<T>().getCount())>>
: std::is_same<decltype(std::declval<T>().getCount()), int>::type { };
(Use declval<T&>
if you want to check that getCount()
can be called on an lvalue.)
If you just check for the existence of a getCount
member, then you get a hard error if a member with that name exists but isn't callable (e.g., a data member).
Although at this point you might as well consider just using something like
template< class T >
struct hasGetCount<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().getCount()), int>::value>> : std::true_type { };
instead of writing the decltype
twice.
这篇关于使用`void_t`检查类是否具有带有特定签名的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!