2012-03-27 20 views
1

Ich möchte die Kompilierung brechen, wenn das Objekt const deklariert ist.Prüfen ob das Objekt const

Die folgende funktioniert nicht:

#include <type_traits> 

struct A { 

    A() : v(0) 
    { 
     static_assert(! std::is_const<decltype(*this)>::value, "declared as const"); 
    } 

    int& AccessValue() const 
    { 
     return const_cast< int& >(v); 
    } 

    int v; 
}; 

int main() 
{ 
    A a1; // ok, this compiles 
    const A a2; // no, this break the compilation 

    a1.AccessValue() = 5; // ok 
    a2.AccessValue() = 6; // OPS 
} 

Also, gibt es eine Möglichkeit, die Zusammenstellung zu brechen, wenn ein Objekt dieses Typs const deklariert wird?

+5

Ich bezweifle, dass es möglich ist. Was willst du erreichen? –

+1

Wenn jemand ein 'const A' bekommt, aber nicht sollte, wird der Compiler schließlich Fehler geben, die im Grunde dasselbe sagen (als const deklariert), so dass Sie nicht wirklich nach solchen Dingen suchen müssen. – Shahbaz

+0

@AlexandreC. Es ist UB, const_cast zu verwenden, um von einem konstanten Verweis auf einen nicht-konstanten Verweis zu wechseln, es sei denn, das Objekt wird als nicht-konstant deklariert. Ich muss const_cast verwenden, möchte aber verhindern, dass Leute Objekte dieses Typs const deklarieren. –

Antwort

3

Du Überschrift in die falsche Richtung.

Der Typ this wird nur durch die Signatur der Methode, in der Sie ihn verwenden, festgelegt. Das heißt, this ist immer vom Typ cv T* const wobei cv den CV-Qualifiern der Methode entspricht.

Daher ist in einem Konstruktor this nur T* const.


const_cast ist ein Code Geruch, in der Regel nur dann sinnvoll, wenn sie mit const -broken Legacy-Bibliotheken ... oder (manchmal), die sie zu verletzen DRY zu vermeiden.In neuem Code sollten Sie es nicht verwenden müssen.

Sie sind mit einer Auswahl links:

  • machen AccessValue nicht-const, da es nicht
  • erklären ist i als mutable zu sein.

Ich würde empfehlen, die ehemalige Lösung zu wählen. Ein private-Attribut zu übergeben, ist bereits schlecht (bricht die Kapselung), es ist auch nicht notwendig, die Korrektheit der const Korrektheit zu verletzen.

+2

'this' ist nie' U const'. Es ist ein rvalue. 'const' macht keinen Sinn für Nicht-Objekt-Rvalues, also gibt es keine Nicht-Klassen-/Nicht-Array-Rvalues ​​dieses Typs –

+0

@ JohannesSchaub-litb: Dies, denke ich, ist es der juristische Ansatz. In der Praxis [ist es qualifiziert] (http://ideone.com/Gzgyg). Vielleicht, weil dies dem Compiler hilft, schlecht geformte Anrufe zu diagnostizieren? (Vermeiden Sie das Hinzufügen von Fremdlogik für 'this') –

+0

nein, in der Praxis gcc hat einen Fehler. –

0

Sie können mehrere Variablen haben, die sich auf dasselbe Objekt beziehen, einige veränderbar und einige konstant. Zum Beispiel:

A a1; 
const A &a2 = a1; 
A * const pa = &a1; 
f(a1); 
.... 
void f(const A &a); 

sollte diese in Ihrem Fall erlaubt sein? Konvertierung von Mutable zu Const ist implizit das Gegenteil ist nicht. Vielleicht, wenn Sie ein Beispiel geben, wird helfen.

EDIT: (als Reaktion auf den geänderten Code) mit einem const-Objekt können Sie nur const Member-Funktion aufrufen. warum nicht haben:

int& AccessValue() 
{ 
    return v; 
} 

eine der Compiler mit beschweren, wenn Sie AccessValue auf einem nicht konstantes Objekt aufrufen.

+0

Modifiziert mein Beispiel. Hoffe, es ist jetzt besser –

1

Für Ihr spezielles Beispiel macht i wandelbar Ihr Ziel erreichen würde:

int& AccessValue() const 
{ 
    return v; 
} 

mutable int v; 

Dies ist aus §7.1.6.1/4 [dcl.type.cv]:

Abgesehen davon, dass Jedes als veränderlich deklarierte Klassenmitglied (7.1.1) kann geändert werden, jeder Versuch, ein konstantes Objekt während seiner Lebensdauer (3.8) zu modifizieren, führt zu undefiniertem Verhalten.

Beachten Sie, dass Sie nicht v mit einem Zeiger-to-Mitglied auf ein konstantes Objekt ändern kann - § 5.5/5 von n3290 Entwurf [expr.mptr.oper]:

[Anmerkung: Es ist nicht möglich, einen Zeiger auf Member zu verwenden, der auf ein veränderbares Member verweist, um ein Const-Klassenobjekt zu ändern. Zum Beispiel

struct S { 
S() : i(0) { } 
mutable int i; 
}; 

void f() 
{ 
const S cs; 
int S::* pm = &S::i; // pm refers to mutable member S::i 
cs.*pm = 88;   // ill-formed: cs is a const object 
} 

- Endnote]

+0

Aber ich habe keinen Zeiger auf Member-Variable. Daher gilt [7.1.6.1/5, letzte C++ 11], dort darf es geändert werden. Es gibt sogar ein Beispiel –

+0

Ja, das veränderbare Mitglied funktioniert. Ich habe nur darauf hingewiesen, dass es einige Dinge gibt, die man nicht machen kann, obwohl das Mitglied veränderbar ist - indem man einen Zeiger auf Mitglied verwendet. Aber solange du das nicht tust, ist es gut. – Mat

Verwandte Themen