使用`void_t`检查类是否具有带有特定签名的方法 [英] Using `void_t` to check if a class has a method with a specific signature

查看:98
本文介绍了使用`void_t`检查类是否具有带有特定签名的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此刻,我使用此方法来检查类是否具有带有特定签名的方法。



参加 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆