我发现类似的问题和答案像这一个.但是,正如我尝试的那样,如果测试成员直接在被测试的类中定义,则此SFINAE测试仅成功.例如以下,类B,D1打印HAS而另外两个打印NOT HAS.有没有一种方法来确定,如果一个类有一个成员,无论是由自己定义,或基类和基类的名称没有在这种情况下,已知的.我的动机是,我想编写一个泛型函数,如果它存在,将调用某个方法(从基础或不基础,参数的类型是通用的,留下其可能的基类型).
#include <iostream>
class HasFoo
{
public :
typedef char Small;
typedef struct {char; char;} Large;
template <typename C, void (C::*) ()> class SFINAE {};
template <typename C> static Small test (SFINAE<C, &C::foo> *)
{
std::cout << "HAS" << std::endl;
}
template <typename C> static Large test (...)
{
std::cout << "NOT HAS" << std::endl;
}
};
class B
{
public :
void foo () {}
};
class D1 : public B
{
public :
void foo () {} // overide
};
class D2 : public B
{
public :
using B::foo;
};
class D3 : public B {};
int main ()
{
HasFoo::test<B>(0);
HasFoo::test<D1>(0);
HasFoo::test<D2>(0);
HasFoo::test<D3>(0);
}
Run Code Online (Sandbox Code Playgroud)
在C++ 03中,遗憾的是这不可能,抱歉.
在C++ 11中,由于其神奇之处,事情变得更加容易decltype.decltype允许您编写表达式来推断其结果的类型,因此您可以完美地命名基类的成员.如果方法是模板,则SFINAE适用于decltype表达式.
#include <iostream>
template <typename T>
auto has_foo(T& t) -> decltype(t.foo(), bool()) { return true; }
bool has_foo(...) { return false; }
struct Base {
void foo() {}
};
struct Derived1: Base {
void foo() {}
};
struct Derived2: Base {
using Base::foo;
};
struct Derived3: Base {
};
int main() {
Base b; Derived1 d1; Derived2 d2; Derived3 d3;
std::cout << has_foo(b) << " "
<< has_foo(d1) << " "
<< has_foo(d2) << " "
<< has_foo(d3) << "\n";
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,ideone有一个版本的gcc,这个版本太旧了,而clang 3.0并不是更好.
不幸的是,至少在 C++03 中这是不可能的,我也怀疑在 C++11 中。
几个重要的点:
publicprivate和protected继承 SFINAE 可能最终无用public方法/继承,HasFoo::test<>可以增强代码以获取多个参数,其中也可以传递基类;
std::is_base_of<>可用于进一步验证基础/派生关系;然后也对基类应用相同的逻辑