Newsgroup: it.comp.lang.c++
Titolo: Problemi con template multiplo

Per gestire in una libreria piu` callback con diverso valore di ritorno 
(void o con valore) ho costruito un oggetto intermedio che uso nella 
procedura di gestione della callback. Il problema che ho e` che se i due 
parametri della callback sono dello stesso tipo l'oggetto mi da un 
errore di tipo:
ttt.cpp: In instantiation of ‘ReturnType<cl, bool, int, int>’:
ttt.cpp:53:   instantiated from here
ttt.cpp:13: error: ‘bool ReturnType<T, R, A, J>::notify(A, R (T::*)(A), 
T*, bool) const [with T = cl, R = bool, A = int, J = int]’ cannot be 
overloaded
ttt.cpp:10: error: with ‘bool ReturnType<T, R, A, J>::notify(J, R 
(T::*)(J), T*, bool) const [with T = cl, R = bool, A = int, J = int]’
In effetti ha ragione, perche' in quel caso:
    bool notify(J arg, R (T::*fnc)(J), T *obj, bool rc) const;
    bool notify(A w, R (T::*fnc)(A), T *obj, bool rc) const;
Sono identiche....
Comunque ecco il codice di un esempio minimale. Definendo 
DIFFERENT_TYPES compila e funziona come dovrebbe, non definendolo da 
l'errore sopra, non e' proprio cortissimo, ma non sono riuscito a 
sintetizzare il problema in meno di due pagine di codice :(
#include <iostream>
struct FakeType1;
struct FakeType2;
template <typename T, typename R, typename A = FakeType1, typename J = 
FakeType2> struct ReturnType {
    bool notify(R (T::*fnc)(void), T *obj, bool rc) const {
         return (obj->*fnc)();
    }
    bool notify(J arg, R (T::*fnc)(J), T *obj, bool rc) const {
         return (obj->*fnc)(arg);
    }
    bool notify(A w, R (T::*fnc)(A), T *obj, bool rc) const {
         return (obj->*fnc)(w);
    }
    bool notify(A w, J arg, R (T::*fnc)(A, J), T *obj, bool rc) const {
         return (obj->*fnc)(w,arg);
    }
};
template <typename T, typename A, typename J> struct ReturnType<T, void, 
A, J> {
    bool notify(void (T::*fnc)(void), T *obj, bool rc) const {
         (obj->*fnc)();
         return rc;
    }
    bool notify(J arg, void (T::*fnc)(J), T *obj, bool rc) const {
         (obj->*fnc)(arg);
         return rc;
    }
    bool notify(A w, void (T::*fnc)(A), T *obj, bool rc) const {
         (obj->*fnc)(w);
         return rc;
    }
    bool notify(A w, J arg, void (T::*fnc)(A, J), T *obj, bool rc) const {
         (obj->*fnc)(w,arg);
         return rc;
    }
};
struct cl {
     void cbk1() { std::cerr << "void cbk1\n"; }
     void cbk2(int arg) { std::cerr << "void cbk2 " << arg << "\n"; }
     bool cbk3(int arg) { std::cerr << "bool cbk3 " << arg << "\n"; 
return true; }
     bool cbk4(int a1, void * a2) { std::cerr << "bool cbk4 " << a1 << 
',' << a2 << "\n"; return true; }
};
int main()
{
    cl c;
    ReturnType<cl,void> r1;
    ReturnType<cl,void,int> r2;
    ReturnType<cl,bool,int> r3;
    r1.notify(&cl::cbk1, &c, true);
    r2.notify(1, &cl::cbk2, &c, true);
    r3.notify(2, &cl::cbk3, &c, true);
#ifdef DIFFERENT_TYPES // cosi' funziona
    ReturnType<cl,bool,int,void *> r4;
    r4.notify(2, (void *) 3, &cl::cbk4, &c, true);
#else // cosi' no...
    ReturnType<cl,bool,int,int> r4;
    r4.notify(2, 3, &cl::cbk4, &c, true);
#endif
}

    r4.notify(2, (void *) 3, &cl::cbk4, &c, true);
Ho provato il codice, ma il blocco #ifdef non viene eseguito, l'ho dovuto 
commentare per far invocare r4.notify()
Inoltre nella chiamata: r4.notify(2, (void *) 3, &cl::cbk4, &c, true);
che tipo di paramentro è il secondo?
La funzione si aspetta un void*, che vuol dire (void*)  3?
E' un cast?
Per quanto riguarda il tuo problema, r5.notify quale metodo dovrebbe 
chiamare? Mi pare che l'unico possibile sia lo stesso chiamato da r4 infatti 
mi pare il solo che accetti tra i suoi parametri il parametro &cl::cbk4 
ovvero puntatore a funzione membro che accetta 2 parametri. 

 Per quanto riguarda il tuo problema, r5.notify
volevo dire r4.notify in riferimento alla seconda invocazione (quella che 
non funziona) 


Ho risolto il problema, specificando un'ulteriore partial specialization 
di ReturnType da utilizzare nel caso in cui i due parametri template 
siano uguali. Sembra funzionare bene in tutti i miei test case, ecco il 
codice, non c'e' piu' simbolo di compilazione perche` il caso che non 
funzionava e` stato messo come r4 e quello di riferimento che funzionava 
come r5:
#include <iostream>
struct FakeType1;
struct FakeType2;
template <typename T, typename R, typename A = FakeType1, typename J = 
FakeType2> struct ReturnType {
    bool notify(R (T::*fnc)(void), T *obj, bool rc) const {
         return (obj->*fnc)();
    }
    bool notify(J arg, R (T::*fnc)(J), T *obj, bool rc) const {
         return (obj->*fnc)(arg);
    }
    bool notify(A w, R (T::*fnc)(A), T *obj, bool rc) const {
         return (obj->*fnc)(w);
    }
    bool notify(A w, J arg, R (T::*fnc)(A, J), T *obj, bool rc) const {
         return (obj->*fnc)(w,arg);
    }
};
template <typename T, typename R, typename A> struct  ReturnType<T, R, 
A, A> {
    bool notify(R (T::*fnc)(void), T *obj, bool rc) const {
         return (obj->*fnc)();
    }
    bool notify(A w, R (T::*fnc)(A), T *obj, bool rc) const {
         return (obj->*fnc)(w);
    }
    bool notify(A w, A arg, R (T::*fnc)(A, A), T *obj, bool rc) const {
         return (obj->*fnc)(w,arg);
    }
};
template <typename T, typename A, typename J> struct ReturnType<T, void, 
A, J> {
    bool notify(void (T::*fnc)(void), T *obj, bool rc) const {
         (obj->*fnc)();
         return rc;
    }
    bool notify(J arg, void (T::*fnc)(J), T *obj, bool rc) const {
         (obj->*fnc)(arg);
         return rc;
    }
    bool notify(A w, void (T::*fnc)(A), T *obj, bool rc) const {
         (obj->*fnc)(w);
         return rc;
    }
    bool notify(A w, J arg, void (T::*fnc)(A, J), T *obj, bool rc) const {
         (obj->*fnc)(w,arg);
         return rc;
    }
};
template <typename T, typename A> struct ReturnType<T, void, A, A> {
    bool notify(void (T::*fnc)(void), T *obj, bool rc) const {
         (obj->*fnc)();
         return rc;
    }
    bool notify(A w, void (T::*fnc)(A), T *obj, bool rc) const {
         (obj->*fnc)(w);
         return rc;
    }
    bool notify(A w, A arg, void (T::*fnc)(A, A), T *obj, bool rc) const {
         (obj->*fnc)(w,arg);
         return rc;
    }
};
struct cl {
     void cbk1() { std::cerr << "void cbk1\n"; }
     void cbk2(int arg) { std::cerr << "void cbk2 " << arg << "\n"; }
     bool cbk3(int arg) { std::cerr << "bool cbk3 " << arg << "\n"; 
return true; }
     bool cbk4(int a1, int a2)
     { std::cerr << "bool cbk4 " << a1 << ',' << a2 << "\n"; return true; }
     bool cbk5(int a1, void * a2)
     { std::cerr << "bool cbk5 " << a1 << ',' << a2 << "\n"; return true; }
};
int main()
{
    cl c;
    ReturnType<cl,void> r1;
    ReturnType<cl,void,int> r2;
    ReturnType<cl,bool,int> r3;
    ReturnType<cl,bool,int,int> r4;
    ReturnType<cl,bool,int,void*> r5;
    r1.notify(&cl::cbk1, &c, true);
    r2.notify(1, &cl::cbk2, &c, true);
    r3.notify(2, &cl::cbk3, &c, true);
    r4.notify(2, 3, &cl::cbk4, &c, true);
    r5.notify(2, (void *)0xdeadbeef, &cl::cbk5, &c, true);
}

     { std::cerr << "bool cbk5 " << a1 << ',' << a2 << "\n"; return true; }
Ecco ho visto che hai aggiunto una funzione che accetta 2 int che prima non 
c'era.