问题保持不变 - 我们可以检测重载的成员函数,而不指定它们的参数,或者使用提到的技巧吗?我知道我可能要求的是不可能的,但要求永远不会有坏处
其实也不是不可能。
它遵循一个最小的工作示例:
template<typename T, typename R, typename... A>
void proto(R(T::*)(A...));
template<typename, typename = void>
constexpr bool has_single_f = false;
template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f))> = true;
struct S {
void f(int) {}
void f(char) {}
};
struct U {
void f() {}
};
int main() {
static_assert(not has_single_f<S>, "!");
static_assert(has_single_f<U>, "!");
}
当然,你需要添加更多的东西来区分成员方法和数据成员,但是添加它们是微不足道的(参见标题type_traits),我尽量让示例保持最小。
基本思想是,如果给定函数重载,则对proto 的调用会失败,因为这是一个模棱两可的调用。
无论如何,由于 SFINAE 规则,错误被丢弃。
不需要按要求指定参数。
还要注意proto 不需要定义,但重要的是它的返回类型是void。否则,您必须稍微修改对decltype 的调用,如下所示:
template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f), void())> = true;
从示例代码中可以看出,static_asserts 验证 f 在 S 中被重载,并且不在 U 中。
上面的例子是基于模板变量,自 C++14 以来它是语言的一部分。
如果您更喜欢与 C++11 一起使用的众所周知的基于结构的解决方案,您可以使用以下检测器:
#include<type_traits>
//...
template<typename, typename = void>
struct has_single_f: std::false_type {};
template<typename T>
struct has_single_f<T, decltype(proto(&T::f))>: std::true_type {};
//...
int main() {
static_assert(not has_single_f<S>::value, "!");
static_assert(has_single_f<U>::value, "!");
}