Newsgroup: it.comp.lang.c++
Titolo: R: Conversioni con template di funzioni

Aspetta...
in pratica, io ho un template di funzione, tipo:
template <class tipo> void f( tipo a, tipo b ) {
    a + b;
}
se passo un oggetto di tipo:
class A {
    public:
        A();
    ....
};
ovvero, in pratica, NON è definito l'operatore +. che viene usato nel
template.
Quindi, passandolo al template, viene dato un errore, dato che questo non
può essere instanziato col tipo A:
Se però il tipo A definisce un operatore di conversione per convertire
l'oggetto al tipo B, su cui + è definito, o magari B ha un costruttore non
explicit che accetta il tipo A, e che quindi può essere usato per creare un
oggetto temporaneo da passare al template, non è comunque possibile (a meno
che non espicito che il template deve usarre il tipo B, nel quale quindi ora
avviene la conversione da A).
Mentre, se invece A è convertibile a int, non dovrebbe essere comunque
possibile dedurre il tipo (dato che la conversione definita dall'utente, o
anche quella standard, non fa parte delle tre ammesse nelle deduzione del
tipo di un parametro, no?), ma con gcc e VC++, però, la cosa funziona. Come
mai?
Se poi il tipo è convertibile in più tipi primitivi diversi, allora c'è
giustamente ambiguità quando viene fatta la somma.
Come penso io, la cosa non dovrebbe funzionare, in base allo standard, no?
--
Marco Iannaccone
marc...@tin.it
ICQ UIN: 18748121     MetalCoder
"This is a new ship, boy, but she's got the right name.
You treat her like a lady, and she'll always bring you home."
    Dr. Leonard H. McCoy to Data - Encounter at Farpoint - Star Trek TNG

 mai?
Il problema non e' mai dedurre il tipo. Il tipo viene sempre dedotto
correttamente. Il problema nasce nella compilazione dell'operator +.
Esempio:
struct A {
};
struct B {
    void operator+(const B&) const;
};
struct C {
    operator B() const;
};
struct D {
    operator int() const;
};
struct E {
    void operator+(const B&) const;
    operator int() const;
};
f(A(),A()); // viene chiamata "void f<A>(A,A)"
f(B(),B()); // viene chiamata "void f<B>(B,B)"
f(C(),C()); // viene chiamata "void f<C>(C,C)"
f(D(),D()); // viene chiamata "void f<D>(D,D)"
f(E(),E()); // viene chiamata "void f<E>(E,E)"
in tutti i casi l'argomento del template viene correttamente dedotto.
Il problema sta nell'istanziazione del template dopo la deduzione dato che non
sempre l'espressione "a+b" contenuta nel corpo della funzione pio' essere
compilata.
In particolare non puo' essere compilata nel caso di A e C, ma puo' essere
compilata nel caso di B, D ed E.
La spiegazione sta nel modo in cui avviene la risoluzione dell'overload (che se
non ricordo male e' la clausola 13.3 e relativi sottoparagrafi). Nel caso degli
operatori (e specificatamente per quelli binari come il nostro +) le funzioni
candidate sono definite:
- se tutti gli operandi sono builtin, si considerano solo gli operatori builtin
- se anch uno solo degli operandi e' una classe allora si considerano tre tipi
di funzioni:
1) metodi (per esempio per "a+b" si considera "(a).operator+(b)")
2) non metodi (per esempio per "a+b" si considera "operator+(a,b)")
3) operatori builtin
Ora abbiamo:
A) nessuno operatore di classe 1 o 2, nessun operatore di classe 3 con parametri
in cui un A puo' essere convertito. Quindi errore.
B) un operatore di classe 1, nessun operatore di classe 2, nessun operatore di
classe 3 con parametri in cui un B puo' essere convertito. Quindi si applica
l'unico operatore applicabile: il membro.
C) nessuno operatore di classe 1 (C non ha membri) o 2, nessun operatore di
classe 3 con parametri in cui un C puo' essere convertito. Quindi errore. La
conversione in B non e' considerata. Lo sarebbe (per il secondo parametro) se ci
fosse un "void C::operator+(const B&)", per esempio. Oppure lo sarebbe per
entrambe gli operatori se invece di "void B::operator+(const B&) const" ci fosse
un "void operator+(const B&,const B&)". Ma non e' cosi'.
D) nessuno operatore di classe 1 o 2, un operatore di classe 3 con parametri in
cui un D puo' essere convertito (il builtin che somma interi). Quindi si applica
l'unico operatore applicabile: il builtin.
E)  un operatore di classe 1, nessun operatore di classe 2, un operatore di
classe 3 con parametri in cui un E puo' essere convertito (il builtin che somma
interi). Quindi tocca gestire l'overload fra il membro ed il builtin. Vince il
membro per le regole di best match (sono quasi certo che la clausola relativa
sia la 13.3.3).
Spero di essere stato chiaro e di non aver scritto cappellate. Mi scuso se il
riferimento al numero delle clausole e' errato, ma ho citato a memoria.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

Ok, tutto chiaro!!!!!
I miei dubbi venivano dal fatto che pensavo che avveniva un a conversione
dei parametri delle funzione template (mentre non è vero, e eventualmente
avvengono sull'operatore chiamato dentro...)
Grazie!!!
--
Marco Iannaccone
marc...@tin.it
ICQ UIN: 18748121     MetalCoder
"This is a new ship, boy, but she's got the right name.
You treat her like a lady, and she'll always bring you home."
    Dr. Leonard H. McCoy to Data - Encounter at Farpoint - Star Trek TNG
"Andrea Ferro" <And...@UrkaDVD.it> ha scritto nel messaggio
news:9gvtu1$rqo$1...@serv1.iunet.it...
