如何在编译时判断类是否包含某个成员函数

JQ.*_*JQ. 4 c++ member-functions compile-time

可能重复:
是否可以编写C++模板来检查函数是否存在?

说有两个类:

struct A{ int GetInt(){ return 10; } };
struct B{ int m; };
Run Code Online (Sandbox Code Playgroud)

我想在以下函数中使用类型A或B的对象

tempate< typename T >
int GetInt( const T & t )
{
   //if it's A, I'll call: return t.GetInt();
   //if its' B, I'll call: return t.m;
}
Run Code Online (Sandbox Code Playgroud)

现在,因为有一大堆类,一些包含GetInt(),一些不包含,我不想为每种类型编写特化,我只想在编译时通过' 包含GetInt()来区分它们',我该怎么做?

Ben*_*igt 6

替换失败不是错误,或更紧凑,SFINAE

但在您的特定情况下,您不需要SFINAE,虚拟成员或任何类似的东西.

你只需要一个普通的重载函数.

int GetInt(A& t) { return t.GetInt(); }
int GetInt(const B& t) { return t.m; }
Run Code Online (Sandbox Code Playgroud)

如果需要在不同版本之间共享代码,则重构它以便有一个调用重载内联函数的模板,所有特定于类型的行为都在内联函数中,并且所有共享行为都在模板中.

对于你的"我有很多课程"的需要,SFINAE看起来或多或少会像这样:

template<typename T>
int GetInt(const T& t, int (T::*extra)() const = &T::GetInt)
{
    return t.GetInt();
}

template<typename T>
auto GetInt(const T& t) -> decltype(t.m)
{
    return t.m;
}
Run Code Online (Sandbox Code Playgroud)

编辑:SFINAE的现实非常丑陋,至少在C++ 0x出现之前.事实上,它开始看起来和GMan的答案一样糟糕.

struct A{ int GetInt() const { return 10; } };
struct B{ int m; };

template<typename T, int (T::*extra)() const>
struct has_mfunc
{
    typedef int type;
};

template<typename T>
typename has_mfunc<T, &T::GetInt>::type GetInt(const T& t)
{
    return t.GetInt();
}

template<typename T, typename U, U (T::*extra)>
struct has_field
{
    typedef U type;
};

template<typename T>
typename has_field<T, int, &T::m>::type GetInt(const T& t)
{
    return t.m;
}

int main(void)
{
   A a;
   B b;
   b.m = 5;
   return GetInt(a) + GetInt(b);
}
Run Code Online (Sandbox Code Playgroud)


GMa*_*ckG 4

从这里窃取,并假设你修复了你的代码,所以GetInt是 const,我们得到:

HAS_MEM_FUNC(GetInt, has_GetInt);

template <bool B>
struct bool_type
{
    static const bool value = B;
};

typedef bool_type<true> true_type;
typedef bool_type<false> false_type;

namespace detail
{
    template <typename T>
    int get_int(const T& pX, true_type)
    {
        return pX.GetInt();
    }

    template <typename T>
    int get_int(const T& pX, false_type)
    {
        return pX.m;
    }
}

template <typename T>
int get_int(const T& pX)
{
    return detail::get_int(pX,
                            has_GetInt<T, int (T::*)() const>::value);
}
Run Code Online (Sandbox Code Playgroud)

但这是一个非常糟糕的设计。您应该解决问题而不是应用补丁。