How to tell if class contains a certain member function in compile time
Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?
假设有两个类:
1 2 | struct A{ int GetInt(){ return 10; } }; struct B{ int m; }; |
我想在下面的函数中使用类型A或B的对象
1 2 3 4 5 6 | 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()或不在编译时"来区分它们,我该怎么做呢?
替换失败不是一个错误,或者更紧凑地说,不是一个错误。
但在您的特定情况下,您不需要sfinae、虚拟成员或类似的任何花哨内容。
您只需要一个普通的重载函数。
1 2 | int GetInt(A& t) { return t.GetInt(); } int GetInt(const B& t) { return t.m; } |
如果有代码需要在不同版本之间共享,请对其进行重构,以便有一个模板调用重载的内联函数,所有特定于类型的行为都在内联函数中,所有共享行为都在模板中。
对于您的"我有许多课程"需求,sfinae或多或少会像这样:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
编辑:SFIEAE的现实更加丑陋,至少在C++0X出现之前。事实上,它开始看起来和GMAN的答案一样糟糕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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); } |
不过,这是个相当糟糕的设计。您应该解决问题,而不是应用补丁。
这正是继承的目的。您可以在运行时轻松地使用"动态"类型的问题。例如,您可以定义一个名为hasGetInt的抽象基类,并从中派生出需要该函数的类,而不是重新创建控制盘。
从技术上讲,它只涉及一些模板arcana,您可以通过谷歌搜索找到,例如
但是,不要这样做。
还有什么事要看情况而定。但是,您的类似乎符合两种不同的"模式",也就是说,如果没有通过类型系统提供这些模式(例如,类似乎不是从两个基类A和B派生的)。然后,一个选项是引入一个特性模板,告诉您包装器模板参数t是模式a还是模式b。专门化每个与默认值不同的相关类的特性。选择默认值以最小化工作。
干杯!