如何调用成员函数只有当对象恰好有它吗? [英] How to call member function only if object happens to have it?
问题描述
可能重复:
是否可以编写一个C ++模板来检查函数的存在?
< blockquote>
我有一个函数
f
,接收一个值val
。有没有任何方法可以调用T
(模板)的val
(如果类型有这样的成员函数)的成员函数?
示例:
struct Bar {
void foo()const {}
};
template< class T>
void f(T const& val){
//有什么方法调用* only *如果foo()在类型T上可用?
// SFINAE技术?
val.foo();
}
int main(){
Bar bar;
f(bar);
f(3.14);听起来像SFINAE技术对我来说,也许使用boost :: enable_if,但是,我们可以使用boost :: enable_if,但是我可以使用boost :: enable_if。我不知道如何使它在这里工作。请注意,我不能轻易地更改示例中的Bar
类型。我知道这很容易,如果Bar
包含一些特定的typedef等,表示该功能可用。
不用说,我不知道
T
的类型集合,f
将被调用。有些具有foo
成员函数,有些不是。解决方案你可以这样做,如下面的测试程序所示(用
GCC 4.7.0或clang 3.1 )。
静态模板函数
has_void_foo_no_args_const< T> :: eval(T const& t)
如果方法void T :: foo()const
存在且为public,将调用t.foo()
如果没有这样的方法,它将
什么都不做。 (当然,如果方法是私有的,编译错误将
结果。)
这个解决方案是从方法内省的
模板我在此处提供了。你
可以读取这个答案以解释SNIFAE逻辑是如何工作的,
,也可以看看该技术如何被推广到参数化
你正在探测的函数签名的属性。#include< iostream>
/ *!模板`has_void_foo_no_args_const< T>`导出一个
布尔常量`value`是true iff`T`提供
````````````````foo static void eval(T const& t)`,
在`t`时调用void`T :: foo()const`,如果这样一个public成员
函数存在并且是无操作if没有这样的成员。
* /
template<类型名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。 sig怎么样? * /
typedef decltype(test(& A :: foo))return_type;
return return_type();
}
/ * SFINAE游戏结束:( * /
template< typename A>
static std :: false_type test(...){
return std :: false_type();
}
/ *这将是`std :: true_type`或`std :: false_type` * /
typedef decltype测试< T>(0,0))类型;
static const bool value = type :: value; / *这是什么?* /
/ *`eval (T const&,std :: true_type)`
在`type` ==`std :: true_type`时委托`T :: foo()`
* /
static void eval(T const& t,std :: true_type){
t.foo();
}
/ *`eval(...)`不匹配的参数* /
static void eval(...){
//这个输出为演示目的删除
std :: cout<<T :: foo称为}
/ *`eval(T const& t)`代表: -
- 类型()`当`type` ==`std :: true_type`
- `eval(...)`否则
* /
static void eval(T const& t){
eval(t,type());
}
};
//用于测试
struct AA {
void foo()const {
std :: cout< AA :: foo()called<< std :: endl;
}
};
//用于测试
struct BB {
void foo(){
std :: cout< BB :: foo()called<< std :: endl;
}
};
//用于测试
struct CC {
int foo()const {
std :: cout< CC :: foo()called<< std :: endl;
return 0;
}
};
//这是所需的`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没有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没有void foo()const)
< std :: endl;
f(3.14);
return 0;
}
此程式输出:
AA有void foo()const
AA :: foo()调用
BB没有void foo()const
T :: foo()没有调用
CC没有void foo()const
T :: foo()没有调用
Double没有void foo()const
T :: foo()不叫
Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?I have a function
f
that receives a valueval
of typeT
(templated). Is there any way to call a member function onval
only if the type has such a member function?Example:
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); }
Sounds like the SFINAE technique to me, maybe using boost::enable_if, but I don't know how to make it work here. Note that I can't easily change the
Bar
type in the example. I know it would be easy ifBar
contained some certain typedef, etc., which signals that the function is available.Needless to say, I don't know the set of types
T
thatf
will be called with. Some have thefoo
member function, some don't.解决方案You can do this as illustrated by the test program below (built with GCC 4.7.0 or clang 3.1).
The static template function
has_void_foo_no_args_const<T>::eval(T const & t)
will invoket.foo()
if the methodvoid T::foo() const
exists and is public. It will do nothing if there is no such method. (And of course a compile error will result if the method is private.)This solution is adapted and extended from the method-introspecting template I contributed here. You can read that answer for an explanation of how the SNIFAE logic works, and also to see how the technique might be generalised to parameterize the properties of the function-signature you are probing.
#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; }
This program outputs:
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
这篇关于如何调用成员函数只有当对象恰好有它吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!