Breve storia: sovraccarico quando è possibile, specializzarsi quando è necessario.
Lunga storia: C++ tratta specializzazioni e sovraccarichi in modo molto diverso. Questo è meglio spiegato con un esempio.
template <typename T> void foo(T);
template <typename T> void foo(T*); // overload of foo(T)
template <> void foo<int>(int*); // specialisation of foo(T*)
foo(new int); // calls foo<int>(int*);
Ora scambiamo gli ultimi due.
template <typename T> void foo(T);
template <> void foo<int*>(int*); // specialisation of foo(T)
template <typename T> void foo(T*); // overload of foo(T)
foo(new int); // calls foo(T*) !!!
Il compilatore esegue la risoluzione di sovraccarico prima ancora di esaminare le specializzazioni. Quindi, in entrambi i casi, la risoluzione di sovraccarico sceglie foo(T*)
. Tuttavia, solo nel primo caso trova foo<int*>(int*)
perché nel secondo caso la specializzazione int*
è una specializzazione di foo(T)
, non foo(T*)
.
Hai citato std::swap
. Questo rende le cose ancora più complicate.
Lo standard dice che è possibile aggiungere specializzazioni allo spazio dei nomi std
. Ottimo, quindi hai un po 'di tipo e ha uno scambio performante quindi ti specializzi solo nello spazio dei nomi swap(Foo&, Foo&)
. Nessun problema.
Ma cosa succede se Foo
è una classe modello? Il C++ non ha una specializzazione parziale delle funzioni, quindi non è possibile specializzare swap
. La tua unica scelta è il sovraccarico, ma lo standard dice che non ti è permesso aggiungere sovraccarichi nello spazio dei nomi std
!
avete due opzioni a questo punto:
creare una funzione swap(Foo<T>&, Foo<T>&)
nel proprio spazio dei nomi, e sperare che venga trovata tramite ADL. Dico "speranza" perché se la libreria standard chiama swap come std::swap(a, b);
, ADL semplicemente non funzionerà.
Ignora la parte dello standard che dice di non aggiungere sovraccarichi e farlo comunque. Onestamente, anche se tecnicamente non è permesso, in tutti gli scenari realistici funzionerà.
Una cosa da ricordare però è che non c'è alcuna garanzia che la libreria standard utilizza swap
a tutti. La maggior parte degli algoritmi utilizza std::iter_swap
e in alcune implementazioni che ho esaminato, non sempre inoltra a std::swap
.
fonte
2011-08-18 13:24:22
grande esempio signore – tenfour
"dico speranza perché" ... Questo punto è stato notato nel WG21 diversi anni fa. Tutti gli implementatori di librerie standard non lo sanno. – MSalters
Risposta meravigliosa, grazie mille. –