关于c ++:如果对象碰巧有它,如何调用成员函数?

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?

我有一个函数f,它接收T类型的值val(模板化)。只有当类型具有这样的成员函数时,才能调用val上的成员函数吗?

例子:

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,但我不知道如何让它在这里工作。注意,我不能轻易地在示例中更改Bar类型。我知道如果Bar包含一些特定的typedef等,这表示函数是可用的,那就很容易了。

不用说,我不知道将调用f的一组类型T。有些具有foo成员函数,有些没有。


您可以按照下面的测试程序(用一般合同条款第4.7.0款或第3.1款)。

静态模板函数has_void_foo_no_args_const::eval(T const & t)。如果方法void T::foo() const存在并且是公共的,将调用t.foo()。它将如果没有这样的方法,什么也不做。(当然,编译错误会如果方法是私有的,则返回结果。)

这个解决方案是从方法内省中改编和扩展的。我在这里提供的模板。你可以阅读这个答案来解释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,它感觉不到直接可行。