2009-07-08 23 views
6

Próbuję wskaźników funkcji członkowskich przechowywać przez szablony tak: (To jest uproszczoną wersją mojego prawdziwego kodu)Przeciążone wskaźnik funkcji członka do szablonu

template<class Arg1> 
void connect(void (T::*f)(Arg1)) 
{ 
    //Do some stuff 
} 

template<class Arg1> 
void connect(void (T::*f)()) 
{ 
    //Do some stuff 
} 

class GApp 
{ 
public: 
    void foo() {} 

    void foo(double d) {} 
}; 

Następnie chcę zrobić jak następuje za co przeciążone metody GAPP:

connect(&GApp::foo); 

Wywołanie to dla foo() jest ok, ale jak mogę nazwać to dla foo(double d)? Dlaczego poniższe czynności nie działają?

connect((&GApp::foo)(double)); 

To da mi

błąd składni: „podwójne” powinien być poprzedzony „)”

nie rozumiem składni, które muszą być wykorzystane tutaj. To może być głupi pomysł, ale czy ktoś może mi w tym pomóc?

+0

Lepiej używać Funktorów zamiast wskaźników funkcyjnych imho. – Drakosha

+0

Cały kod jest częścią implementacji mechanizmu Signal and Slot. Tak więc, litener (który ma slot) nie chce wiedzieć o systemie. Tak więc, nie mogę powiedzieć słuchaczowi, żeby to zrobił, zrób to ...... – Morpheus

Odpowiedz

6

Twój kod zapisany nie kompiluje się. Zrobiłem kilka "założeń" o tym, co chciałeś zrobić i zmieniłeś kod.

Podsumowując, można nazwać właściwą funkcję jednoznacznie określający typ parametru Funkcja:

connect<double> (&GApp::foo); 

Jeżeli metody connect są członkami szablonu klasy, to jest tylko konieczne, aby określić typ klasy raz :

template <typename T> class A 
{ 
public: 
    template<class Arg1> 
    void connect(void (T::*f)(Arg1)) 
    { 
    //Do some stuff 
    } 

    void connect(void (T::*f)()) 
    { 
    //Do some stuff 
    } 
}; 

class GApp 
{ 
public: 
    void foo() {} 
    void foo(double d) {} 
}; 


int main() 
{ 
    A<GApp> a; 
    a.connect (&GApp::foo);   // foo() 
    a.connect<double> (&GApp::foo); // foo (double) 
} 

UPDATE:

w odpowiedzi na nowe próbki kodu, wszystko w formacja jest przekazywana. "Rzadki" przypadek to przypadek "signal_void", ponieważ w tym miejscu sygnał ma argument szablonu, ale funkcja składowa nie. Dlatego mamy specjalny przypadek, że przykład, a następnie skończyliśmy. Poniższy teraz kompiluje:

template <class Arg = void> 
class signal {}; 
signal<double> signal_double; 
signal<> signal_void; 

// Arg1 is deduced from signal<Arg1> and then we use it in the declaration 
// of the pointer to member function 
template<class T, class Arg1> 
void connect (signal<Arg1>& sig, T& obj, void (T::*f)(Arg1)) {} 

// Add special case for 'void' without any arguments 
template<class T> 
void connect (signal<> & sig, T& obj, void (T::*f)()) {} 


void bar() 
{ 
    GApp myGApp; 

    //Connecting foo() 
    connect(signal_void, myGApp, &GApp::foo); // Matches second overload 

    //Connecting foo(double) 
    connect(signal_double, myGApp, &GApp::foo); // Matches first overload 
} 
+0

Hej! Dzięki za wysiłek. Przepraszam, zapomniałem powiedzieć, że mój kod nie jest kompletny. To dlatego, że usunąłem szablon szablonu Signal, aby uprościć kod. BTW, tak, twoja metoda działa dobrze. Opublikuję mój oryginalny kod, czy możesz na to patrzeć? Dzięki – Morpheus

+1

Wohooooo .... tak. Pokazujesz mi ścieżkę. Teraz wszystkie działają poprawnie. Dziękuję Ci bardzo. – Morpheus

1

Można spróbować wyraźnie odlewania wskaźnik, aby to wiedzieć, który z nich wybrać, tak:

connect((void (GApp::*)(double))&GApp::foo); 

disclaimer: nie testowano go

+0

Dziękuję za ans. Tak, działa ... – Morpheus

+0

To nie może być bezpieczne: rzutowanie jest po prostu funkcją na wskaźniku GApp :: foo. Nie zmieni to zawartości wskaźnika. – xtofl

+0

Mam teorię, że jest bezpieczna, zobacz moją odpowiedź dla szczegółów. Nie potwierdziłem tego jeszcze w standardzie, ponieważ mam silne podejrzenie, że język w standardzie będzie pasował do Stroustrup w C++ PL i to jest pytanie, które jest trochę rozczochrane. –

0

To działa,

typedef void (GApp::*MemberFunctionType)(double); 
    MemberFunctionType pointer = &GApp::foo; 


    connect(MemberFunctionType); 

Dlaczego tak jest?

EDYTUJ

hmm .. tak. Jest to to samo, co rozwiązanie newacct. Czy ktoś może podać rozwiązanie?

+0

Moja odpowiedź wyjaśnia, dlaczego to działa, odwołując się do Stroustrup i założenia, że ​​to, co mówi o wskaźnikach funkcji, dotyczy również wskaźników funkcji członkowskich. –

0

Korzystanie z biblioteki boost :: function ...

#include <boost/function.hpp> 

template<class Arg1> 
void connect(boost::function1<void, Arg1*> fn) 
{ 
    //Do some stuff 
} 

template<class Arg1> 
void connect(boost::function2<void, Arg1*, double> fn) 
{ 
    //Do some stuff 
} 

class GApp 
{ 
public: 
    void foo() {} 

    void foo(double d) {} 
}; 


int main() 
{ 
    boost::function1<void,GApp*> f1 = (void (GApp::*)(void)) &GApp::foo; 
    boost::function2<void,GApp*,double> f2 = (void (GApp::*)(double)) &GApp:foo; 
    connect(f1); 
    connect(f2); 
    return 0; 
} 
+0

Hej! Dzięki za ans. Nie jest twoja (void (GApp :: *) (double)) & GApp: foo; tak samo jak rozwiązanie newacct, (void (GApp :: *) (double)) i GApp :: foo. Ale xtofl powiedział, że to nie jest bezpieczne :( – Morpheus

+0

xtofl zaktualizował swój komentarz, by powiedzieć, że wydaje się bezpieczny, ponieważ lepiej jest używać obiektów funkcyjnych niż wskaźników funkcyjnych, to wszystko – Anshul

0

Mój kod oryginalny jest tak,

złącza ....

template<class T, class Arg1> 
void connect(signal<Arg1>& sig,T& obj, void (T::*f)()) 
{ 
// sig.insert(new GFunction<T, Arg1>(&obj,f)); 
} 

template<class T, class Arg1 
void connect(signal<Arg1>& sig,T& obj, void (T::*f)(Arg1)) 
{ 
// sig.insert(new GFunction<T, Arg1>(&obj,f)); 
} 

Sygnały ...

signal<double> signal_double; 
signal<> signal_void; 

aplikacji ...

class GApp 
{ 
public: 
    void foo() {} 

    void foo(double d) {} 
}; 

Finaly, łącząc ...

//Connecting foo() 
     connect(signal_void, myGApp, &GApp::foo()); //Ok 

//Connecting foo(double) 
     connect(signal_double, myGApp, &GApp::foo()); // but ERROR! 

Istnieje szablon classs sygnałów (co nie ma tu wzmianki). Mam nadzieję, że teraz jest bardziej przejrzysta sytuacja. (czy jest to to samo co poprzednie?). To drugie połączenie zadziała, jeśli nie ma foo() (tylko foo (podwójne)). To właśnie mnie koduję. :(

5

C++ Programming Language, 3E, Sekcja 7.7, P159.

Można wziąć adres przeciążonej funkcji poprzez przypisanie lub inicjowania wskaźnik do funkcji w takim przypadku, rodzaj tarcza służy do wyboru ze zbioru przeciążonych funkcji. na przykład:

void f(int); 
int f(char); 

void (*pf1)(int) = &f; // void f(int); 
int (*pf2)(char) = &f; // int f(char); 
void (*pf3)(char) = &f; // error: no void f(char) 

o ile wiem (nie sprawdzone), to samo odnosi się do funkcji składowych Więc rozwiązanie jest prawdopodobnie. podzielone na dwie linie:

connect((&GApp::foo)(double)); 

staje:

void (GApp::*tmp)(double) = &GApp::foo; 
connect(tmp); 

zmienne tmp ;-)

Przypuszczam, że obsada newacct jest zbyt bezpieczne, dokładnie z tego samego powodu nigdy nie zadzwoni. Przesyłanie do void (GApp::*)(double) jest zdefiniowane tak, jak inicjowanie tymczasowego typu void (GApp::*)(double). Ponieważ wyrażenie użyte do zainicjowania tego jest &GApp::foo, oczekiwałbym, że ta sama magia zostanie zastosowana do rzutowania, jak ma to miejsce w przypadku każdej innej inicjalizacji z przeciążoną funkcją. Stroustrup nie mówi "inicjowanie zmiennej wskaźnik-funkcja", mówi "inicjowanie wskaźnika do funkcji". To powinno zawierać tymczasowe.

Więc jeśli wolisz jedno-liner:

connect((void (GApp::*)(double))(&GApp::foo)); 

Jednak jestem przy założeniu, że średnia ma tę samą ideę spójności jak ja, a ja nie sprawdziłem.

+0

THANKS! Dlatego właśnie obsada zadziała! – xtofl

+0

I mówią, że C++ jest trudne do zrozumienia! ;-) –

Powiązane problemy