2010-11-09 8 views
8

Ich bin mit dem folgenden Problem konfrontiert. Betrachten Sie die folgende Klasse:Nicht zulassen, Zeiger/Verweis auf Const zu einem temporären Objekt in C++ (keine 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; 
}; 

und diese Funktion eine doppelte

double fun() {return 1.0;} 

Rückkehr Wenn wir jetzt

double x = 1.0; 
const double xc = 1.0; 

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

gut so weit haben, aber:

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

Ist Es gibt eine Möglichkeit, Ref zu ändern (die Art und Weise, wie Sie bevorzugen) aber nicht die Funktion Spaß, so dass die letzte Zeile einen Kompilierungsfehler zurückgibt? Bitte beachten Sie, dass Sie die Konstruktorsignatur ändern können (solange ich die Referenz wie vorgesehen initialisieren kann).

Antwort

2

Sie mögen nicht die Syntax, um es zu verwenden, aber den Konstruktor nehmen Sie einen Zeiger anstelle einer Referenz. Sie können nicht einmal einen Const-Zeiger auf ein Temporäres setzen.

Zumindest nicht, ohne sie durch eine andere Wrapper Schmuggel, die hoffentlich den Code macht offensichtlich falsch (TM): template <typename T> T *reftoptr(T &t) { return &t; }

Das heißt, wenn Sie mit dieser die Art und Weise reference_wrapper verwendet wird, die Benutzer tatsächlich wollen, um Provisorien zu erfassen. Solange das Ref-Objekt im selben Voll-Ausdruck auch temporär ist wie das temporäre, das es erfasst, denke ich, dass es in Ordnung ist. So zum Beispiel

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

Dies ist (für mich) das am nächsten zu dem angegebenen Problem (mit auch interessanten Überlegungen, besonders dem letzten), Danke für Ihre Hilfe! – stepelu

3

Nein, und Ihr Code kann auch mit einer normalen Referenz gebrochen werden. Dokumentieren Sie einfach die Tatsache, dass das übergebene Objekt persistent sein muss.

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

+1. Geben Sie in der Dokumentation klar an, wie es verwendet werden muss. Es liegt jedoch nicht in Ihrer Verantwortung, Missbrauch Ihrer Klasse zu berücksichtigen. – ereOn

+0

Der Zweck dieser Einschränkung besteht darin, Benutzern zu helfen. Da es in diesem Fall ziemlich einfach ist, den Benutzern zu helfen, denke ich nicht, dass es von der Hand zu weisen ist. Entledigen Sie sich ausführlich, wenn es irgendeinen Grund gibt, warum es den Benutzern überhaupt nicht hilft ;-) –

1

Verwenden Sie ein Zeigerargument, um Ihr Zeigerelement zu initialisieren. Verwenden Sie keine (const) Referenz dafür - verwenden Sie einen Zeiger, um einen Zeiger zu initialisieren.

Ich habe einige Probleme mit Tracking-Referenzen in der Vergangenheit hatte, und obwohl es nicht direkt auf Ihre Frage in engen Zusammenhang steht, könnte man diese beiden Themen interessant finden:

0

Sie können eine Vorlage verwenden. U& wird zu double& abgeleitet, und das wird nicht an Rvalues ​​gebunden.

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; 
};