如何调用成员函数只有当对象恰好有它吗? [英] How to call member function only if object happens to have it?

查看:119
本文介绍了如何调用成员函数只有当对象恰好有它吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能重复:

是否可以编写一个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 value val of type T (templated). Is there any way to call a member function on val 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 if Bar contained some certain typedef, etc., which signals that the function is available.

Needless to say, I don't know the set of types T that f will be called with. Some have the foo 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 invoke t.foo() if the method void 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆