目前,我using this method to check if a class has a method with a specific signature.
在参加Walter E. Brown's metaprogramming CppCon2014 talk之后,我开始想知道在这种特定情况下是否可以使用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 { };
如果decltype(T::type)
是有效表达式,has_type_data_member<T>
将是真正的编译时常量。因此,我们确信T
有一个名为data
的成员字段。
我想使用相同的方法来检查类型T
是否具有带特定名称和特定签名的方法。
假设我想检查T
是否有一个名为getCount()
的方法返回int
。这就是我期望的工作((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 { };
不幸的是,static_assert
测试没有通过。
我做错了什么?在这种情况下是否可以使用void_t
?
奖金问题:
我可以使用宏来定义这样的辅助结构:
DEFINE_METHOD_CHECKER(hasGetCount, getCount);
// ...
static_assert(hasGetCount<ClassWithGetCount>::value == true, "");
是否可以先避免定义struct
然后检查结构的值?我的意思是,是否可以使用宏来编写这样的东西?例如:
static_assert(CHECK_METHOD(ClassWithGetCount, getCount)::value == true, "");
答案 0 :(得分: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 { };
(如果您想检查左值是否可以调用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 { };
而不是两次写decltype
。
答案 1 :(得分: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 {};
(的 Ideone live code 强>)
希望在C ++ 17发布时,我们可以使用Concepts Lite更轻松地完成此任务:
template <typename T>
concept bool hasGetCount = requires (T t) {
{ t.getCount() } -> int;
};
答案 2 :(得分:0)
如果您还想检查函数的参数及其返回类型,类似于Casey的建议
template<typename... > struct Voider { using Type = void; };
template<typename... TArgs> using void_t = typename Voider<TArgs...>::Type;
template<class, typename, class = void>
struct hasGetCount : false_type { };
template< class T, typename Ret, typename... Args>
struct hasGetCount<T, Ret(Args...),
void_t<decltype(std::declval<Ret&>()
= std::declval<T>().getCount(std::declval<Args>()...))
>> : std::is_same<
decltype(std::declval<T().getCount(std::declval<Args>()...)),
Ret>::type {};
用法:
class A {
public:
int member;
int getCount() {return 0;}
};
static_assert( hasGetCount<A, int(void)>::value , "A" );