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

时间:2010-10-18 23:44:59

标签: c++ compile-time member-functions

  

可能重复:
  Is it possible to write a C++ template to check for a function's existence?

说有两个班级:

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

我想在以下函数中使用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;
}

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

4 个答案:

答案 0 :(得分:6)

Substitution Failure Is Not An Error, or more compactly, SFINAE

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

你只需要一个普通的重载功能。

int GetInt(A& t) { return t.GetInt(); }
int GetInt(const B& t) { return t.m; }

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

对于你的“我有很多课程”的需要,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;
}
编辑: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);
}

答案 1 :(得分:4)

here窃取,并假设您修改了代码以使GetInt为常量,我们得到:

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);
}

这是非常糟糕的设计。您应该修复问题而不是应用补丁。

答案 2 :(得分:0)

从技术上讲,它只涉及一些模板arcana,您可以通过谷歌搜索找到它,例如has_member等。关闭袖口,在检测代码中,如果我要写这样的话,我只是从有问题的类派生出来,并检查派生类'成员的大小。

但是,不要这样做。

还有什么要做的。但是看起来你的类符合两个不同的“模式”,可以这么说,没有那些模式可以通过类型系统获得(比如,似乎这些类不是从两个基类A和B派生的)。然后一个选项是引入一个traits模板,告诉你包装器模板参数T是模式A还是B.专门化每个相关类的特征,它们与默认值不同。选择默认值以尽量减少工作。

干杯&amp;第h。,

答案 3 :(得分:0)

这正是继承的目的。您可以在运行时轻松使用dynamic_cast作为问题类型。例如,您可以定义一个名为HasGetInt的抽象基类,并从中派生需要该函数的类,而不是重新发明轮子。