2017-01-31 3 views
2

Ich möchte eine Memberfunktion als Parameter senden, aber es wird nicht kompilieren. Warum funktioniert der Code nicht? Hier, was ich geschrieben habe. Wenn ich stattdessen ein Lambda übergebe, funktioniert es.Senden Sie Mitglied Funktionszeiger als Parameter innerhalb einer anderen Elementfunktion

void global_func(std::function<void(void)>f) 
{ 
    f(); 
} 

class goo 
{ 
public: 
    goo() { } 

    void func1() 
    { 
     std::function<void(void)> fp = &goo::func2; // get a pointer to the function func2 . Error here or next line 

     global_func(fp); 
    } 

    void func2(void) 
    { 

    } 

}; 


void main() 
{ 
    goo g1; 
    g1.func1(); 

} 

Hier wird der Compiler-Ausgang (mein Programmname ist tryvector.cpp)

1>------ Build started: Project: TryVector, Configuration: Debug Win32 ------ 
1> TryVector.cpp 
1>e:\program files\microsoft visual studio 12.0\vc\include\functional(506): error C2664: 'void std::_Func_class<_Ret,>::_Set(std::_Func_base<_Ret,> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,> *' 
1>   with 
1>   [ 
1>    _Ret=void 
1>   ] 
1>   Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 
1>   e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Do_alloc<_Myimpl,_Fret(__thiscall goo::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Fret=void 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1> ,   _Fty=void (__thiscall goo::* const &)(void) 
1>   ] 
1>   e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Do_alloc<_Myimpl,_Fret(__thiscall goo::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Fret=void 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1> ,   _Fty=void (__thiscall goo::* const &)(void) 
1>   ] 
1>   e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset_alloc<_Fret,goo,,std::allocator<std::_Func_class<_Ret,>>>(_Fret (__thiscall goo::* const)(void),_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Fret=void 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1>   ] 
1>   e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset_alloc<_Fret,goo,,std::allocator<std::_Func_class<_Ret,>>>(_Fret (__thiscall goo::* const)(void),_Alloc)' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Fret=void 
1> ,   _Alloc=std::allocator<std::_Func_class<void,>> 
1>   ] 
1>   e:\program files\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset<void,goo,>(_Fret (__thiscall goo::* const)(void))' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Fret=void 
1>   ] 
1>   e:\program files\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset<void,goo,>(_Fret (__thiscall goo::* const)(void))' being compiled 
1>   with 
1>   [ 
1>    _Ret=void 
1> ,   _Fret=void 
1>   ] 
1>   d:\vc++ my files\tryvector\tryvector\tryvector.cpp(42) : see reference to function template instantiation 'std::function<void (void)>::function<void(__thiscall goo::*)(void)>(_Fx &&)' being compiled 
1>   with 
1>   [ 
1>    _Fx=void (__thiscall goo::*)(void) 
1>   ] 
1>   d:\vc++ my files\tryvector\tryvector\tryvector.cpp(42) : see reference to function template instantiation 'std::function<void (void)>::function<void(__thiscall goo::*)(void)>(_Fx &&)' being compiled 
1>   with 
1>   [ 
1>    _Fx=void (__thiscall goo::*)(void) 
1>   ] 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 
+0

können Sie die Ausgabe des Compilers anhängen? – jdehesa

+0

Haben Sie die Fehlermeldung gelesen? Normalerweise sagt es dir, was schief gelaufen ist. – user2079303

+0

@ user2079303: Nicht in diesem Fall, besonders für einen Anfänger. –

Antwort

6

Ein std::function<void(void)> ist etwas, das einfach aufgerufen werden kann, ohne Parameter und ohne weiteren Kontext.

goo:func2 ist jedoch eine nicht statische Elementfunktion. Es kann nicht einfach angerufen werden; benötigt es eine goo Instanz. Es ist, als hätte es einen unsichtbaren Parameter: void func2(goo* const this). Und das macht Sinn, weil func2 wahrscheinlich einige andere nicht statische goo Mitglieder benötigt, um seine Arbeit zu erledigen.

Sie haben mehrere Möglichkeiten:

  • ein Lambda Verwenden this zu erfassen, d.h .: auto const fp = [this] { func2(); };. Denken Sie daran, dies entspricht auto const fp = [this] { this->func2(); };.
  • Wenn func2 keine nicht statischen Elemente von goo benötigt, dann machen Sie die Funktion static.
  • Verwenden Sie std::bind.
+1

Das funktioniert auch nur ich habe ein Semikolon nach func2() Tippfehler – ark1974

+0

@ ark1974: Fest, danke :) –

+0

Kleine Nitpick, die 'func2' ist nicht definiert als' const' so der Zeiger ist auch nicht. Dies ist auch wichtig für das Lambda. Das 'This' muss für nicht konstante Elementfunktionen als veränderbar markiert werden. – luk32

2

Ein Mitglied Funktionszeiger kann nicht in ein std::function<void(void)> gewickelt werden, da die Elementfunktion ein implizites Argument: Der Zeiger this. Der von Ihnen definierte Funktions-Wrapper benötigt jedoch nur Null-Callables.

Lösung 1: Ändern Sie den Funktionswrapper in std::function<void(goo*)>. Dazu müssen Sie auch global_func ändern, um das Argument zu übergeben.

Lösung 2: Verwenden Sie std::bind, um einen Funktor zu generieren, in dem der implizite Zeiger an eine Instanz gebunden ist.

+0

Ich denke, deine ersten Sätze sollten "Kann nicht" sagen. –

+0

@ChristianHackl Ich brach den Satz beim Bearbeiten. Fest. – user2079303

2

Es ist, weil die Elementfunktion keine übereinstimmende Signatur hat. Es enthält auch implizit this.

#include <functional> 

void global_func(std::function<void(void)>f) 
{ 
    f(); 
} 

class goo 
{ 
public: 
    goo() { } 
    void func1() 
    { 
     std::function<void(void)> fp = std::bind(&goo::func2, this); 
     global_func(fp); 
    } 

    void func2(void) { } 
}; 

int main() 
{ 
    goo g1; 
    g1.func1(); 
} 

Lambda arbeitet, weil es this erfassen: Sie können beispielsweise durch Bindung der Member-Funktion und this machen.

Statische Funktion würde auch funktionieren, weil es keinen impliziten this Parameter hat.

Im Grunde brauchen Sie eine Instanz, auf die Sie die Funktionen aufrufen, also in Ihrem Fall this scheint vernünftig.

+0

Danke, es hat funktioniert. – ark1974

0

Da eine nicht statische Elementfunktion keine Funktion ist. In gängigen Implementierungen enthält es einen versteckten Zeiger auf das Objekt, auf dem es sich befindet (this).

Nur statische Methoden können wie Funktionen verwendet werden.

2

Elementfunktionen haben einen impliziten this Parameter als ihren ersten Parameter.

goo::func2(void) 

ist eigentlich

goo::func2(goo* const this); 

Sie eines von zwei Dingen tun:

Ändern Sie die Signatur von global_func eine Art std::function<void(goo*)>

Gebrauch akzeptieren std::bind den this Parameter zu binden .

std::function<void(void)> fp = std::bind(&goo::func2, this); 
global_func(fp); 
+0

Genauer gesagt, 'goo :: func2 (goo * const this);' für nichtkonstante Elementfunktionen und 'goo :: func2 (goo const * const this);' für konstante Elementfunktionen. –

2

Ihr Bedarf entweder func2 eine statische Elementfunktion der Klasse zu machen, oder es zu this binden, wenn Sie es zu einem std::function konvertieren:

std::function<void()> fp = std::bind(&goo::func2, this); 

etwas mehr - es gibt ein paar sind andere ungewöhnliche Konstrukte in Ihrem Code. Obwohl sie arbeiten, aber sie sind nicht gut C++ Praxis:

void func2(void)

dies C Style, in C++ einfach void func2() schreiben. Auch: Schließlich

void global_func(std::function<void()>f) // <-- not void(void) 

, int main() nicht void main()

Verwandte Themen