2016-05-02 15 views
5

È possibile fornire una conversione automatica per una classe template istanziata con tipi di puntatori const e non-const?Conversione automatica dei tipi per modelli con tipi di puntatori const/non-const

In particolare, considerare quanto segue:

template <typename T> 
class A { 
public: 
    operator A<const T>() 
    { 
     return A<const T>(); 
    } 
}; 

int main() 
{ 
    A<const int> a1; 
    A<int> a2; 
    // Works fine; invokes operator A<const T>() 
    a1 = a2; 

    A<const int*> a3; 
    A<int*> a4; 
    // Fails to compile: no viable overloaded '=' 
    a3 = a4; 

    return 0; 
} 

E 'possibile fornire una conversione esplicita per i tipi con argomenti template puntatore? Come apparirebbe nella definizione di A?

Come una domanda bonus/background, perché funziona sopra per gli argomenti del modello non puntatore, ma non per gli argomenti del modello di puntatore?

+1

Per 2), poiché 'const T' con' T' essendo 'int *' è 'int * const', non' const int * ' –

+0

Quindi, che dire' const T' e 'T const *' vuoi convertire 'T' e' T * 'implicitamente in essi esattamente? Vorresti, ad esempio, un 'A >' per convertire implicitamente in un 'A >'? O se 'U' deriva da' T', vuoi 'A ' per convertire implicitamente in 'A '? – Yakk

risposta

4

La fonte della confusione è la costanza del puntatore rispetto alla costanza del pointee. Il setup che hai ora converte uno T in uno const T. Se sostituisci int per T funziona, int diventa const int. Tuttavia, se si sostituisce int * si ottiene int * const, non const int *. Il T ottiene un const, che è un puntatore, quindi il puntatore diventa const, non l'oggetto a cui punta.
Il seguente codice funziona:

A<int*const> a5; 
A<int*> a6; 
// compiles 
a5 = a6; 

È possibile fare alcune cose difficili come

operator A<std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>>() 
{ 
    return {}; 
} 

per fare a3 = a4; compilazione, ma bisogna stare molto attenti che queste conversioni in realtà fanno quello che si suppone fare (l'esempio sopra riportato in modo errato (?) consente la conversione da a const int * perché remove_pointer non fa nulla se il tipo specificato non è un puntatore, avrebbe bisogno di enable_if + is_pointer che diventa piuttosto complicato velocemente).

+0

Potrebbe essere un'idea migliore quella di specializzarsi parzialmente per i puntatori. –

+0

Probabilmente vuoi anche supportare 'T const * const *' da 'T **', ma non 'T const **'. Un po 'di test SFINAE potrebbe farlo. – Yakk