How to call member function only if object happens to have it?
本问题已经有最佳答案,请猛点这里访问。
Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?
我有一个函数
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | struct Bar { void foo() const {} }; template<class T> void f(T const& val) { // Is there any way to call *only* if foo() is available on type T? // SFINAE technique? val.foo(); } int main() { Bar bar; f(bar); f(3.14); } |
对我来说,听起来像是sfinae技术,可能使用boost::enable_if,但我不知道如何让它在这里工作。注意,我不能轻易地在示例中更改
不用说,我不知道将调用
您可以按照下面的测试程序(用一般合同条款第4.7.0款或第3.1款)。
静态模板函数
这个解决方案是从方法内省中改编和扩展的。我在这里提供的模板。你可以阅读这个答案来解释snifae逻辑是如何工作的,同时也要了解如何将技术概括为参数化正在探测的函数签名的属性。
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #include <iostream> /*! The template `has_void_foo_no_args_const<T>` exports a boolean constant `value` that is true iff `T` provides `void foo() const` It also provides `static void eval(T const & t)`, which invokes void `T::foo() const` upon `t` if such a public member function exists and is a no-op if there is no such member. */ template< typename T> struct has_void_foo_no_args_const { /* SFINAE foo-has-correct-sig :) */ template<typename A> static std::true_type test(void (A::*)() const) { return std::true_type(); } /* SFINAE foo-exists :) */ template <typename A> static decltype(test(&A::foo)) test(decltype(&A::foo),void *) { /* foo exists. What about sig? */ typedef decltype(test(&A::foo)) return_type; return return_type(); } /* SFINAE game over :( */ template<typename A> static std::false_type test(...) { return std::false_type(); } /* This will be either `std::true_type` or `std::false_type` */ typedef decltype(test<T>(0,0)) type; static const bool value = type::value; /* Which is it? */ /* `eval(T const &,std::true_type)` delegates to `T::foo()` when `type` == `std::true_type` */ static void eval(T const & t, std::true_type) { t.foo(); } /* `eval(...)` is a no-op for otherwise unmatched arguments */ static void eval(...){ // This output for demo purposes. Delete std::cout <<"T::foo() not called" << std::endl; } /* `eval(T const & t)` delegates to :- - `eval(t,type()` when `type` == `std::true_type` - `eval(...)` otherwise */ static void eval(T const & t) { eval(t,type()); } }; // For testing struct AA { void foo() const { std::cout <<"AA::foo() called" << std::endl; } }; // For testing struct BB { void foo() { std::cout <<"BB::foo() called" << std::endl; } }; // For testing struct CC { int foo() const { std::cout <<"CC::foo() called" << std::endl; return 0; } }; // This is the desired implementation of `void f(T const& val)` template<class T> void f(T const& val) { has_void_foo_no_args_const<T>::eval(val); } int main() { AA aa; std::cout << (has_void_foo_no_args_const<AA>::value ? "AA has void foo() const" :"AA does not have void foo() const") << std::endl; f(aa); BB bb; std::cout << (has_void_foo_no_args_const<BB>::value ? "BB has void foo() const" :"BB does not have void foo() const") << std::endl; f(bb); CC cc; std::cout << (has_void_foo_no_args_const<CC>::value ? "CC has void foo() const" :"CC does not have void foo() const") << std::endl; f(cc); std::cout << (has_void_foo_no_args_const<double>::value ? "Double has void foo() const" :"Double does not have void foo() const") << std::endl; f(3.14); return 0; } |
该程序输出:
1 2 3 4 5 6 7 8 | AA has void foo() const AA::foo() called BB does not have void foo() const T::foo() not called CC does not have void foo() const T::foo() not called Double does not have void foo() const T::foo() not called |
如果您有typedef bool has_f或static(编译时可用的东西),我想您可以进行分支(使用boost元编程函数),或者提供两个模板,一个模板将在定义了_f的情况下实例化,另一个模板则不定义。没有关于t的元数据,imho,它感觉不到直接可行。