L'operatore condizionale non è in grado di risolvere i puntatori di funzione membro sovraccarico
-
07-07-2019 - |
Domanda
Sto riscontrando un piccolo problema con i puntatori a funzioni membro sovraccaricate in C ++. Il seguente codice viene compilato correttamente:
class Foo {
public:
float X() const;
void X(const float x);
float Y() const;
void Y(const float y);
};
void (Foo::*func)(const float) = &Foo::X;
Ma questo non viene compilato (il compilatore si lamenta che i sovraccarichi sono ambigui):
void (Foo::*func)(const float) = (someCondition ? &Foo::X : &Foo::Y);
Presumibilmente questo ha a che fare con il compilatore che ordina il valore di ritorno dell'operatore condizionale separatamente dal tipo di puntatore a funzione? Posso aggirarlo, ma sono interessato a sapere come le specifiche dicono che tutto ciò dovrebbe funzionare poiché sembra un po 'poco intuitivo e se c'è un modo per aggirarlo senza ricadere su 5 righe di if-then-else .
Sto usando MSVC ++, se questo fa la differenza.
Grazie!
Soluzione
Dalla sezione 13.4 / 1 (" Indirizzo della funzione sovraccaricata, " [over.over]):
L'uso di un nome di funzione sovraccarico senza argomenti viene risolto in alcuni contesti in una funzione, un puntatore a funzione o un puntatore a funzione membro per una funzione specifica dal set di sovraccarico. Un nome di modello di funzione viene considerato come un insieme di funzioni sovraccariche in tali contesti. La funzione selezionata è quella il cui tipo corrisponde al tipo di destinazione richiesto nel contesto. Il target può essere
- un oggetto o riferimento in fase di inizializzazione (8.5, 8.5.3),
- il lato sinistro di un compito (5.17),
- un parametro di una funzione (5.2.2),
- un parametro di un operatore definito dall'utente (13.5),
- il valore restituito di una funzione, funzione operatore o conversione (6.6.3) o
- una conversione di tipo esplicita (5.2.3, 5.2.9, 5.4).
Il nome della funzione di sovraccarico può essere preceduto dall'operatore
& amp;
. Un nome di funzione sovraccarico non deve essere utilizzato senza argomenti in contesti diversi da quelli elencati. [ Nota: qualsiasi serie di parentesi ridondanti che circonda il nome della funzione sovraccarica viene ignorata (5.1). ]
Il target che speravi fosse selezionato dall'elenco sopra era il primo, un oggetto in fase di inizializzazione. Ma c'è un operatore condizionale nel modo, e gli operatori condizionali determinano i loro tipi dai loro operandi, non da alcun tipo di destinazione.
Poiché le conversioni di tipo esplicito sono incluse nell'elenco delle destinazioni, è possibile eseguire il cast di ogni espressione puntatore-membro nell'espressione condizionale separatamente. Prima farei un typedef:
typedef void (Foo::* float_func)(const float);
float_func func = (someCondition ? float_func(&Foo::X) : float_func(&Foo::Y));
Altri suggerimenti
Prova:
void (Foo::*func1)(const float) = &Foo::X;
void (Foo::*func2)(const float) = &Foo::Y;
void (Foo::*func3)(const float) = (someCondition ? func1:func2);
Il problema è che il tipo di risultato del trinary dell'operatore è determinato dai suoi argomenti.
In questa situazione, non è possibile determinare il tipo di risultato poiché i tipi di input hanno opzioni multipla. Solo quando viene determinato il tipo di operatore trinario che tenterà l'incarico.
Esempio:
class Foo {
public:
void X(float x) {}
void Y(float y) {}
float X() const;
};
typedef void (Foo::*Fff)(float);
Fff func = &Foo::X;
Fff func2 = true ? (Fff)&Foo::X : (Fff)&Foo::Y;
int main(){
return 0;
}
Devi lanciare & amp; Foo :: X immediatamente per risolvere il sovraccarico. Si noti che se si commenta il float X () sovraccarico, non è necessario farlo.
Sembra che il compilatore non sia abbastanza intelligente da dedurre il tipo di ritorno richiesto di un'espressione ternaria (questo potrebbe essere un bug).