2016-04-21 6 views
0

Angenommen, ich habeWenn Klasse A seine Konstruktionsparameter ändert, kann ich const A mit const Parametern initialisieren?

class A final { 
    int& ir; 
public: 
    A(int& x) : ir(x) { } 
    void set(int y) { ir = y; } // non-const method! 
    int get() const { return ir; } 
}; 

und

const int i; 

Offensichtlich ich nicht

A a(i); 

da diese Pausen Konstantheit haben kann. Aber ich kann auch nicht haben

const A a(i); 

trotz der Tatsache, dass dies constness de-facto nicht brechen wird. C++ unterstützt keine "Const-Only" -Ktors, z.B. in diesem Fall würde man eine const int& nehmen. Gibt es eine Möglichkeit const A a Einwickeln einen Verweis auf i zu erhalten - anders als

A a(const_cast<int &>(i)) 

?

+1

Könnten Sie bitte beschreiben, was Sie erreichen wollen? – paceholder

+0

"trotz nicht brechen connessness"? Ich verstehe nicht. Sie können anschließend nach 'a.ir' schreiben. Ich würde sagen, das ist ziemlich unsicher. –

+0

Was in den Sinn kommt, ist 'Klasse A {Variante v; A (const int & a): a (a) {} A (int & a): a (a) {}};'. nicht sicher, ob das so funktioniert, wie es ist, aber es könnte ein Anfang sein. Dann besuchen Sie 'a.v' mit einem' [] (auto && a) {} ' –

Antwort

0
class A { 
    const int& ir; // <<-- it's a const int. 
    /* ... */ 
public: 
    A(int& x) : ir(x) { } 
}; 
+0

Nicht was ich meinte, ich möchte ein paar nicht-konstante A's und einige Konst A's, und in der Lage sein, die Const A's mit 'const int &' s – einpoklum

1

Es ist komisch, aber

class A final { 
    union{ 
    int& ir; 
    const int &cir; 
    }; 
public: 
    A(int& x) : ir(x) { } 
    A(const int& x) : cir(x) { } 
    void set(int y) { ir = y; } // non-const method! 
    int get() const { return ir; } 
}; 

int main(int argc, char *argv[]) 
{ 
    const int cv = 8; 
    int v = 6; 
    A a(cv); 
    std::cout << a.get() << std::endl; 
    a.set(v); 
    std::cout << a.get() << std::endl; 
    return 0; 
} 

Auch Ihr Set und Verfahren opearates auf Werte keine Referenzen bekommen, es ist so aussieht wie Sie etwas falsch

+0

zu konstruieren, würde ich fast für diese Einfachheit upvote, wenn nur die Standard erlaubt Referenzdaten Mitglieder in Gewerkschaften. – user2079303

+0

@ user2079303 das würde auch nicht wirklich funktionieren: Sein Beispiel kompiliert und erzeugt undefiniertes Verhalten, da ihn nichts daran hindert, 'a.set (v)' aufzurufen. Sie müssen sich daran erinnern, welchen Konstruktor Sie verwendet haben, indem Sie beispielsweise eine 'boost :: variant' verwenden oder sie manuell speichern. –

+0

@ JohannesSchaub-litt guten Punkt. Es scheint, dass sich die Einfachheit in diesem Fall nicht lohnt. – user2079303

3

C++ nicht über ein Konzept vollständig konstante Klassen, und der Compiler wird möglicherweise nicht ausgeführt, wenn die Referenz int & nur als const int & verwendet wird. Also im Grunde kannst du es nicht tun.

4

"Const" bedeutet, dass das Objekt zwischen dem Konstruktorende und dem Destruktorbeginn konstant ist (während der Konstruktion muss es möglich sein, das Objekt zu ändern). C++ hat keinen "Vorbereitungskonstruktor", der für konstante Objekte bevorzugt wird.

Sie können diese Problemumgehung versuchen, indem Sie anwenden. Dies ist zum Zeitpunkt der Kompilierung nicht vollständig typsicher, erkennt jedoch Fehler zur Laufzeit, indem mindestens eine Ausnahme ausgelöst wird.

#include <boost/variant.hpp> 
#include <iostream> 

class R { 
    boost::variant<int&, const int&> v; 
public: 
    R(int&v):v(v) { } 
    R(const int&v):v(v) { } 

    // works with both 
    int get() const { 
    return boost::apply_visitor( 
     [](int x){return x;}, v); 
    } 

    // only works for non-const A. If at construction, a const 
    // int was passed, throws an error at runtime 
    void set(int x) { 
    boost::get<int&>(v) = x; 
    } 
}; 


int main() { 
    int a = 0; 
    const int b = a; 
    R r1(a); 
    R r2(b); 
    const R r3(a); 
    std::cout << r1.get() << r2.get() << r3.get(); 
    // r3.set(1); // compile error 
    r1.set(1); // works 
    r2.set(1); // runtime error 
} 
+0

1. Ist die Variante nicht bereits im Standard? 2. Wie langsam ist apply_visitor? – einpoklum

+1

@einpoklum Ich glaube, Variante ist in C++ 17 (ich könnte falsch liegen). Definitiv nicht C++ 11 oder C++ 14. apply_visitor ist grundsätzlich eine switch-Anweisung (vielleicht ein bisschen mehr Phantasie im Boost-impl, ich habe keine Ahnung). Aber da beide Switch-Fälle hier denselben Code ausführen (einfach eine Bewegung von einem int), würde ich erwarten, dass der Compiler sie faltet und den gesamten apply_visitor inline einfügt. Im Zweifelsfall ignorieren, bis es Leistungsprobleme verursacht :) –

1

Dies ist nicht, wie ich den Code schreiben würde, aber es funktioniert irgendwie. Wenn Sie eine Template-Klasse aus der const-Variablen konstruieren, wird die set() -Funktion auch const definiert und ändert den Status nicht. Durch Konstruieren aus einer nichtkonstanten Variablen kann die Mengenfunktion den Zustand ändern.

#include <iostream> 
#include <string> 
#include <type_traits> 

template<typename T> 
class A 
{ 
    T &_i; 
public: 
    A(T &i) : _i(i) {} 

    template <typename D = T, 
      typename = std::enable_if_t<std::is_const<D>::value 
             > 
      > 
    void set(T i) const { std::cout << "Do nothing on set" << std::endl; } 

    template <typename D = T, 
      typename = std::enable_if_t<!std::is_const<D>::value> 
      >  
    void set(T i) { std::cout << "Do something on set" << std::endl; } 
}; 

int main() 
{ 
    { 
     std::cout << "Construct from NON const variable" << std::endl; 
     int b = 5; 

     A<decltype(b)> a(b); 

     a.set(3); 
    } 

    { 
     std::cout << "Construct from const variable" << std::endl; 
     int const b = 5; 

     A<decltype(b)> a(b);  

     a.set(3); 
    } 
} 

Diese Drucke:

Construct from NON const variable 
Do something on set 
Construct from const variable 
Do nothing on set 
Verwandte Themen