La ragione fondamentale di questa ambiguità (conforme alle norme) sembra essere all'interno del costo di conversione: la risoluzione di sovraccarico tenta di ridurre al minimo le operazioni eseguite per convertire un argomento nel parametro corrispondente. Un array è efficacemente il puntatore al suo primo elemento, tuttavia, decorato con alcune informazioni sul tipo in fase di compilazione. Una conversione da matrice a puntatore non costa più di ad es. salvare l'indirizzo della matrice stessa o inizializzarne un riferimento. Da quella prospettiva, l'ambiguità sembra giustificata, sebbene concettualmente non sia intuitivo (e potrebbe essere scadente). In effetti, questa argomentazione si applica a tutte le trasformazioni di Lvalue, come suggerito dalla seguente citazione. Un altro esempio:
void g() {}
void f(void(*)()) {}
void f(void(&)()) {}
int main() {
f(g); // Ambiguous
}
Il seguente è standardese obbligatoria. Le funzioni che non sono specializzazioni di alcuni template funzione sono preferite rispetto a quelle che sono se entrambe sono ugualmente una corrispondenza altrettanto buona (si veda [over.match.best]/(1.3), (1.6)). Nel nostro caso, la conversione eseguita è una conversione da matrice a puntatore, che è una trasformazione Lvalue con rank di corrispondenza esatta (in base alla tabella 12 in [over.ics.user]). [Over.ics.rank]/3:
Il primo punto elenco esclude la nostra conversione (poiché è una trasformazione Lvalue).Il secondo richiede una differenza nei ranghi, che non è presente, in quanto entrambe le conversioni hanno un match rank esatto; Le "regole nel paragrafo seguente", cioè in [over.ics.rank]/4, non coprono neanche le conversioni da matrice a puntatore.
Quindi credici o no, nessuna delle due sequenze di conversione è migliore dell'altra, e quindi viene selezionato il -overload char const*
.
soluzione possibile: Definire il secondo overload come modello funzione così, allora calci ordinamento parziale e seleziona il primo.
template <typename T>
auto foo(T s)
-> std::enable_if_t<std::is_convertible<T, char const*>{}>
{
std::cout << "raw, size=" << std::strlen(s) << std::endl;
}
Demo.
correlati: http://stackoverflow.com/questions/5347444/overload-resolution-and-arrays-which-function-should-be-called – 0x499602D2
'foo <> ("ciao");' chiamerà il modello se aiuta Penso che sia un modo semplice per rifiutare il modello. E per forzare il non-template usa '(& pippo) (" ciao ")' - puoi prendere l'indirizzo di un modello diverso da modello, ma non di un modello. –