C++: comportamento della specializzazione del modello di funzione con riferimento a rvalue
-
12-11-2019 - |
Domanda
Sto cercando di implementare una funzione di dereferenziazione del puntatore condizionale.L’idea di base è la seguente:
return is_pointer(arg) ? *arg : arg
Per limitare il numero di specializzazioni necessarie, sto tentando di utilizzare riferimenti rvalue nel caso in cui arg
non è un puntatore.Ecco la mia attuale implementazione (the std::cout
sono presenti esclusivamente a scopo di debug):
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T&& t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return t;
}
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == true, typename std::remove_pointer< T >::type& >::type deref(T t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return *t;
}
Ora, ottengo un comportamento piuttosto strano con GCC 4.6.Il primo sovraccarico viene utilizzato sia per i tipi non puntatori che per i tipi puntatore.Ovviamente, quando si utilizza un tipo di puntatore, entra in conflitto con il secondo sovraccarico.Se commento il secondo e chiamo quanto segue utilizzando il primo...
int q;
int *p = &q;
deref(p);
...l'output della console corrispondente è:
0
Pi
Com'è possibile che un tipo non puntatore (secondo std::is_pointer
) è anche un tipo di puntatore (secondo typeid
) nello stesso contesto?Il conflitto sorge tra entrambi i sovraccarichi a causa di std::is_pointer
segnalazione errata p
come tipo non puntatore.Inoltre, quando sostituisco il riferimento del valore r con un riferimento standard nel primo sovraccarico:
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T& t)
Non è più in conflitto con il secondo sovraccarico...Semplicemente non capisco cosa stia succedendo.A proposito, utilizzando il secondo sovraccarico si ottiene (come ci si aspetterebbe):
1
Pi
Grazie per l'aiuto.
Soluzione
Per quanto ho capito
template <T>
void foo(T&&)
significa che se T
è un lvalue, verrà dedotto come riferimento (T = int*&
nel tuo caso) e dopo il collasso dei riferimenti int*&&&
restituisce un riferimento lvalue regolare int*&
.Se non fosse così, questa sintassi catturerebbe qualsiasi cosa come riferimento a un valore.Considerando che il punto è associare lvalue ai riferimenti lvalue e rvalue ai riferimenti rvalue.
E is_pointer<int*&>
non è vero.Quindi potresti provare a candidarti remove_reference<T>
.
Altri suggerimenti
Nel tuo primo sovraccarico T viene dedotto come int*&. Prova il tuo primo sovraccarico da utilizzare remove_reference<T>::type
Nel tuo abilita_if-test e output.