Domanda

Si consideri la situazione in cui ha bisogno un modello di funzione di trasmettere un argomento mantenendolo del valore assegnabile-ness nel caso in cui si tratta di un valore assegnabile non-const, ma è essa stessa agnostica a ciò che l'argomento è in realtà, come in:

template <typename T>
void target(T&) {
    cout << "non-const lvalue";
}

template <typename T>
void target(const T&) {
    cout << "const lvalue or rvalue";
}


template <typename T>
void forward(T& x) {
    target(x);
}

Quando x è un rvalue, invece di T essere dedotto a un tipo costante, dà un errore:

int x = 0;
const int y = 0;

forward(x); // T = int
forward(y); // T = const int
forward(0); // Hopefully, T = const int, but actually an error
forward<const int>(0); // Works, T = const int

Sembra che per forward a rvalues ??manico (senza chiamare per argomenti espliciti template) ci deve essere un sovraccarico forward(const T&), anche se il corpo sarebbe stato un esatto duplicato.

C'è un modo per evitare questo doppioni?

È stato utile?

Soluzione

Questo è un problema noto e lo scopo di riferimenti rvalue in C ++ 0x. Il problema non ha soluzione generica in C ++ 03.

C'è qualche ragione storica arcaica per cui questo si verifica che è molto inutile. Ricordo di aver chiesto una sola volta e la risposta mi ha depresso notevolmente.

Altri suggerimenti

In generale, questo brutto problema con i modelli di dovrebbe per richiedere la duplicazione, perché la semantica in cui una variabile è const o no, o un riferimento o no, sono ben distinti.

La soluzione C ++ 11 a questo è "decltype", ma è una cattiva idea perché non fa altro composto e sistema di tipo già rotto.

Non importa quello che dice la standard o del Comitato, "int const" non è e non sarà mai un tipo. Né sarà "int &" mai essere un tipo. Quindi un parametro di tipo in un modello non dovrebbe mai essere consentito di collegarsi a tali non-tipi, e per fortuna per la detrazione è questo il caso. Purtroppo è ancora possibile forzare esplicitamente questa sostituzione senza principi.

Ci sono alcune regole idiote che cercano di "correzione" di questo problema, come ad esempio "const const int" riducendo al "int const", io non sono nemmeno sicuro che cosa succede se si ottiene "int & &": ricordo ancora standard non conta "int &" come un tipo, c'è un tipo "int lvalue", ma questo è diverso:

int x;       // type is lvalue int
int &y = x;  // type is lvalue int

La giusta soluzione a questo problema è in realtà abbastanza semplice: ogni cosa è un oggetto mutabile. Buttate via "const" (non è che utile) e buttare via riferimenti, lvalue e rvalues. E 'abbastanza chiaro che tutti i tipi di classe sono indirizzabili, rvalue o no (il puntatore "this" è l'indirizzo). Ci fu un vano tentativo da parte del comitato di vietare l'assegnazione da e per affrontare rvalues ??.. le opere di casi di indirizzamento, ma è facilmente sfuggito con un cast banale. Il caso assegnazione non funziona affatto (perché l'assegnazione è una funzione membro e rvalues ??sono non-const, si può sempre assegnare a un rvalue digitato classe).

In ogni caso il modello di meta-programmazione di folla hanno "decltype" e con che trovi la codifica di una dichiarazione comprese le "const" e "&" bit e quindi si può scomporre che codifica utilizzando diversi operatori di libreria. Questo non poteva essere fatto prima perché queste informazioni non sono in realtà di tipo informativo ( "ref" è in realtà di memorizzazione allocazione informazioni).

Quando x è un rvalue

Ma x non è mai un rvalue, perché i nomi sono lvalue.

C'è un modo per evitare questo doppioni?

C'è un modo in C ++ 0x:

#include <utility>

template <typename T>
void forward(T&& x)   // note the two ampersands
{
    target(std::forward<T>(x));
}

Grazie a regole che crollano di riferimento, il std::forward<T>(x) espressione è dello stesso valore-categoria come l'argomento alla propria funzione di avanti.

Supponendo che non ci sono argomenti k, come mi risulta l'unica "soluzione" in C ++ 03 è scrivere manualmente 2 funzioni ^ k inoltro assumono ogni possibile combinazione di parametri & e const&. Per l'illustrazione, immaginate che target() effettivamente preso 2 parametri. Si sarebbe quindi bisogno di:

template <typename T>
void forward2(T& x, T& y) {
    target(x, y);
}

template <typename T>
void forward2(T& x, T const& y) {
    target(x, y);
}

template <typename T>
void forward2(T const& x, T& y) {
    target(x, y);
}

template <typename T>
void forward2(T const& x, T const& y) {
    target(x, y);
}

Ovviamente questo diventa molto ingombrante per grandi k, riferimenti quindi rvalue in C ++ 0x come altre risposte hanno menzionato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top