2015-12-02 15 views
17

Betrachten Sie den folgenden Code ein:Zeiger auf Funktionsmember: Was bedeutet `R (* C :: *) (Args ...) '?

template <class> 
struct test: std::integral_constant<int, 0> {}; 
template<class R, class C, class... Args> 
struct test<R(C::*)(Args...)>: std::integral_constant<int, 1> {}; 
template<class R, class C, class... Args> 
struct test<R(*C::*)(Args...)>: std::integral_constant<int, 2> {}; 
template<class R, class C, class... Args> 
struct test<R(**C::*)(Args...)>: std::integral_constant<int, 3> {}; 
template<class R, class C, class... Args> 
struct test<R(C::**)(Args...)>: std::integral_constant<int, 4> {}; 
template<class R, class C, class... Args> 
struct test<R(C::***)(Args...)>: std::integral_constant<int, 5> {}; 

Ich habe absolut keine Ahnung, was (*C::*), (**C::*), (C::**) und (C::***) bedeuten. Ich möchte ein Beispiel für eine test<decltype(f)>, deren value würde gleich 2, 3, 4 und 5 sein. Plus, in diesem Fall, wie lautet die Syntax für f, die die Member-Funktion aufrufen würde?

Antwort

18

Betrachten this example:

struct s { 
    void test1(); 
    void(*test2)(); 
    void(**test3)(); 
}; 

int main() { 
    static_assert(test<decltype(&s::test1)>::value == 1); 
    static_assert(test<decltype(&s::test2)>::value == 2); 
    static_assert(test<decltype(&s::test3)>::value == 3); 

    auto test4 = &s::test1; 
    static_assert(test<decltype(&test4)>::value == 4); 

    auto test5 = &test4; 
    static_assert(test<decltype(&test5)>::value == 5); 
} 

Hier werden die Typen sind:

R(C::*)(Args...) - Ein Zeiger auf eine Memberfunktion.
R(*C::*)(Args...) - Ein Zeiger auf ein Datenelement, das ein Funktionszeiger ist.
R(**C::*)(Args...) - Ein Zeiger auf ein Datenelement, das ein Zeiger auf einen Funktionszeiger ist.
R(C::**)(Args...) - Ein Zeiger auf einen Zeiger auf eine Elementfunktion.
R(C::***)(Args...) - Ein Zeiger auf einen Zeiger auf einen Zeiger auf eine Elementfunktion.

diese nennen, sollten Sie einen slightly modified example:

struct s { 
    void test1() {std::cout << "test1\n";} 
    void(*test2)() = [] {std::cout << "test2\n";}; 

    void(*test3Helper)() = [] {std::cout << "test3\n";}; 
    void(**test3)() = &test3Helper; 

    void test4() {std::cout << "test4\n";} 
    void test5() {std::cout << "test5\n";} 
}; 

int main() { 
    s obj; 

    auto test4 = &s::test4; 

    auto test5Helper = &s::test5; 
    auto test5 = &test5Helper; 

    (obj.*(&s::test1))(); 
    (*(obj.*(&s::test2)))(); // note that the dereference is unnecessary 
    (**(obj.*(&s::test3)))(); // note that the second dereference is unnecessary 
    (obj.**(&test4))(); 
    (obj.***(&test5))(); 
} 

Hinweis in jedem Fall, dass, wenn Sie eine Variable mit dem Wert der entsprechenden &[s::]testN haben, Sie (&[s::]testN) mit diesen Variablen ersetzen können. Beachten Sie auch, dass ich für test2 und test3 deneferenziert habe, bis ich die Funktion zurückbekomme, anstatt den Funktionszeiger zu Illustrationszwecken.

+0

Danke! Könnten Sie ein Beispiel geben, wenn 's' einen Funktionsmember' int f (int x) {return x;} 'hat und' testN' sich darauf bezieht, wie lautet die Syntax zum Ausführen von 'testN' auf einer Variablen? – Vincent

+0

@Vincent, ich kam dazu. Eine Sekunde. – chris