下面给出了在https://ideone.com/mxIVw3上发布的针对您的问题的有效解决方案- 另请参见实时示例。
这个问题在某种意义上是C++中继承方法推导父类的后续。在我的回答中,我定义了一个类型特征member_class
,它从给定的指向成员函数类型的指针中提取一个类。下面我们使用更多的特征来分析然后综合回这样的类型。
首先,member_type
提取签名,例如void (C::*)()
给出void()
:
template <typename M> struct member_type_t { };
template <typename M> using member_type = typename member_type_t <M>::type;
template <typename T, typename C>
struct member_type_t <T C::*> { using type = T;};
然后,member_class
提取类,例如void (C::*)()
给出C
:
template<typename>
struct member_class_t;
template<typename M>
using member_class = typename member_class_t <M>::type;
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...)> { using type = C; };
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...) const> { using type = C const; };
// ...other qualifier specializations
最后,member_ptr
在给定类和签名的情况下合成一个指向成员函数类型的指针,例如C
+ void()
give void (C::*)()
:
template <typename C, typename S>
struct member_ptr_t;
template <typename C, typename S>
using member_ptr = typename member_ptr_t <C, S>::type;
template <typename C, typename R, typename ...A>
struct member_ptr_t <C, R(A...)> { using type = R (C::*)(A...); };
template <typename C, typename R, typename ...A>
struct member_ptr_t <C const, R(A...)> { using type = R (C::*)(A...) const; };
// ...other qualifier specializations
前两个特征需要更多的专业化,以使不同的限定符更通用,例如const/volatile
或引用限定符。有 12 种组合(或包括数据成员在内的 13 种);一个完整的实现在这里。
这个想法是任何限定符都member_class
从指向成员函数的指针类型转移到类本身。然后member_ptr
将限定符从类传回指针类型。虽然限定符在类类型上,但可以使用标准特征自由操作,例如添加或删除const
、左值/右值引用等。
现在,这是你的is_foo
测试:
template <typename T>
struct is_foo {
private:
template<
typename Z,
typename M = decltype(&Z::foo),
typename C = typename std::decay<member_class<M>>::type,
typename S = member_type<M>
>
using pattern = member_ptr<C const, void()>;
template<typename U, U> struct helper{};
template <typename Z> static auto test(Z z) -> decltype(
helper<pattern<Z>, &Z::foo>(),
// All other requirements follow..
std::true_type()
);
template <typename> static auto test(...) -> std::false_type;
public:
enum { value = std::is_same<decltype(test<T>(std::declval<T>())),std::true_type>::value };
};
给定类型Z
,别名模板获取成员指针pattern
的正确类型,提取其'ed 类和签名,并合成一个具有类和签名的新指针到成员函数类型,即。这正是您所需要的:它与您的原始硬编码模式相同,类型由正确的类(可能是基类)替换,如.M
decltype(&Z::foo)
decay
C
S
C const
void()
void (C::*)() const
Z
C
decltype
图形化:
M = void (Z::*)() const -> Z + void()
-> Z const + void()
-> void (Z::*)() const == M
-> SUCCESS
M = int (Z::*)() const& -> Z const& + int()
-> Z const + void()
-> void (Z::*)() const != M
-> FAILURE
事实上,S
这里不需要签名,所以也不需要member_type
. 但是我在这个过程中使用了它,所以为了完整起见,我把它包括在这里。它在更一般的情况下可能有用。
当然,所有这些都不适用于多个重载,因为decltype
在这种情况下不起作用。