使用`void_t`检查类是否具有特定签名的方法

Vit*_*meo 7 c++ templates void template-meta-programming c++14

目前,我正在使用此方法来检查类是否具有特定签名的方法.

在参加了Walter E. Brown的元编程CppCon2014演讲之后,我开始想知道是否void_t可以在这种特殊情况下使用它来使代码更清晰,更易读.

但是我在思考方面遇到了麻烦 void_t- 到目前为止我理解这void_t可以帮助我在编译时确定表达式是否有效.

例:

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 { };
Run Code Online (Sandbox Code Playgroud)

如果decltype(T::type)是有效表达式,则为has_type_data_member<T>真正的编译时常量.因此,我们确信T有一个成员字段data.

我想使用相同的方法来检查类型T是否具有具有特定名称和特定签名的方法.

假设我想检查是否T有一个名为getCount()return 的方法int.这是我期望的工作((Ideone.com链接)):

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 { };
Run Code Online (Sandbox Code Playgroud)

不幸的是,static_assert测试没有通过.

我究竟做错了什么?void_t在这种情况下可以使用吗?

奖金问题:

  • 如何检查方法签名是否等于用户在原始实现中传递的签名?
  • 我可以使用宏来定义这样的辅助结构,如下所示:

     DEFINE_METHOD_CHECKER(hasGetCount, getCount);
     // ...
     static_assert(hasGetCount<ClassWithGetCount>::value == true, "");
    
    Run Code Online (Sandbox Code Playgroud)

    是否可以避免必须先定义struct第一个然后检查结构的值?我的意思是,是否可以使用宏来编写这样的东西?例:

     static_assert(CHECK_METHOD(ClassWithGetCount, getCount)::value == true, "");
    
    Run Code Online (Sandbox Code Playgroud)

T.C*_*.C. 6

首先,命名非静态成员函数的id-expression不能用作未评估的操作数(例如操作数decltype).此外,您应该检查整个函数调用表达式是否格式正确,而不仅仅是否有一个名为的成员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 { };
Run Code Online (Sandbox Code Playgroud)

(declval<T&>如果要检查是否getCount()可以在左值上调用,请使用.)

如果您只是检查是否存在getCount成员,那么如果具有该名称的成员存在但不可调用(例如,数据成员),则会出现硬错误.

虽然在这一点上你也可以考虑使用类似的东西

template< class T >
struct hasGetCount<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().getCount()), int>::value>> : std::true_type { };
Run Code Online (Sandbox Code Playgroud)

而不是写decltype两次.

  • `declval <T>`产生一个xvalue,所以如果要检查是否可以在左值上调用`getCount()`,请使用`declval <T&>`(与ref-qualifiers相关). (2认同)

Cas*_*sey 6

您可以使用void_t以轻松验证返回类型getCount是否可转换为int:

template< class, class = void >
struct hasGetCount : false_type { };

template< class T >
struct hasGetCount<T,
  VoidT<
    decltype(std::declval<int&>() = std::declval<T>().getCount())
  >> : std::true_type {};
Run Code Online (Sandbox Code Playgroud)

(Ideone实时代码)

希望在C++ 17推出时,我们可以使用Concepts Lite更轻松地完成这项工作:

template <typename T>
concept bool hasGetCount = requires (T t) {
  { t.getCount() } -> int;
};
Run Code Online (Sandbox Code Playgroud)

  • 虽然这种检查仅适用于`=`的lhs上的非类型类型,否则,您正在检查可分配性.同样,就我看来,它不适用于函数类型和数组(直接). (5认同)