2010-11-09 13 views
8

Sono di fronte al seguente problema. Si consideri il seguente classe:Non consentire il prelievo di puntatore/riferimento a const a un oggetto temporaneo in C++ (senza C++ 0X)

//Will be similar to bost::reference_wrapper 
template<class T> 
class Ref { 
public: 
    explicit Ref(T& t) : m_ptr(&t) {} 
private: 
    T* m_ptr; 
}; 

e questa funzione restituisce un doppio

double fun() {return 1.0;} 

Se ora abbiamo

double x = 1.0; 
const double xc = 1.0; 

Ref<double> ref1(x); //OK 
Ref<const double> refc1(cx); //OK 

bene finora, però:

//Ref<double> ref2(fun()); //Fails as I want it to 
Ref<const double> refc2(fun()); //Works but I would like it not to 

Is c'è un modo per modificare Ref (come te preferisci) ma non è divertente la funzione, in modo che l'ultima riga restituisca un errore in fase di compilazione? Si noti che è possibile modificare la firma del costruttore (a condizione che sia in grado di inizializzare il Ref come previsto).

risposta

2

Potrebbe non piacerti la sintassi per usarlo, ma fare in modo che il costruttore prenda un puntatore invece di un riferimento. Non puoi prendere nemmeno un puntatore const su un temporaneo.

Almeno, non senza contrabbando attraverso un altro involucro che rende spera il codice ovviamente sbagliato (TM): template <typename T> T *reftoptr(T &t) { return &t; }

Detto questo, se si sta utilizzando questo il modo reference_wrapper viene utilizzato, gli utenti possono effettivamente vuoi per catturare i provvisori. Finché l'oggetto Ref è anche un temporaneo nella stessa espressione completa del temporaneo che cattura, penso che sia OK. Ad esempio,

some_algorithm(iterator, anotherit, static_cast<Ref<const double> >(fun())); 
+0

Questo è (per me) il più vicino al problema dichiarato (con anche considerazioni interessanti, specialmente l'ultimo), grazie per l'aiuto! – stepelu

3

No, e il codice può essere rotto anche con un riferimento normale. Basta documentare il fatto che l'oggetto passato deve essere persistente.

double *x = new double; 
Ref<double> ref(*x); 
delete x;  
+0

+1. Indicare chiaramente nella documentazione come deve essere usato. Ma non è tua responsabilità rendere conto degli abusi della tua classe. – ereOn

+0

Lo scopo di questa restrizione è aiutare gli utenti. Dal momento che è abbastanza facile aiutare gli utenti in questo caso, non penso che dovrebbe essere respinto in modo definitivo. Rilasciarlo a lungo, in tutti i dettagli, se c'è qualche motivo per cui non aiuta gli utenti dopotutto ;-) –

1

Utilizzare un argomento puntatore per inizializzare il membro del puntatore. Non utilizzare un riferimento (const) per questo: utilizzare un puntatore per inizializzare un puntatore.

Ho avuto alcuni problemi con il monitoraggio riferimenti in passato, e anche se non è direttamente correlato alla tua domanda, si potrebbe trovare queste due thread interessante:

0

È possibile utilizzare un modello. U& viene dedotto a double& e non verrà associato ai valori rvalue.

template<class T> 
class Ref { 
public: 
    template<typename U> 
    explicit Ref(U& t, 
       typename boost::enable_if< 
       boost::is_convertible<U, T&> 
       >::type * = 0) 
    : m_ptr(&t) {} 
private: 
    T* m_ptr; 
}; 
Problemi correlati