Frage

Puh, das ist ein langer Titel war.

Hier ist mein Problem. Ich habe eine Template-Klasse in C ++ bekam und ich bin eine Überlastung der Operator []. Ich habe sowohl eine konstante und eine nicht-const-Version, mit der nicht-const-Version durch Bezugnahme Rückkehr so ??dass Elemente in der Klasse können als so geändert werden:

myobject[1] = myvalue;

Das alles funktioniert, bis ich einen boolean als Template-Parameter. Hier ist ein vollständiges Beispiel, das zeigt der Fehler:

#include <string>
#include <vector>
using namespace std;

template <class T>
class MyClass
{
    private:
        vector<T> _items;

    public:

        void add(T item)
        {
            _items.push_back(item); 
        }

        const T operator[](int idx) const
        {
            return _items[idx];
        }

        T& operator[](int idx)
        {
            return _items[idx];
        }

};


int main(int argc, char** argv)
{
    MyClass<string> Test1;      //  Works
    Test1.add("hi");
    Test1.add("how are");
    Test1[1] = "you?";


    MyClass<int> Test2;         //  Also works
    Test2.add(1);
    Test2.add(2);
    Test2[1] = 3;


    MyClass<bool> Test3;        // Works up until...
    Test3.add(true);
    Test3.add(true);
    Test3[1] = false;           // ...this point. :(

    return 0;
}

Der Fehler ist ein Compiler-Fehler und die Nachricht ist:

error: invalid initialization of non-const reference of type ‘bool&’ from a temporary of type ‘std::_Bit_reference’

Ich habe gelesen und festgestellt, dass STL einige temporären Datentypen verwendet, aber ich verstehe nicht, warum es funktioniert mit allem, was außer einem Bool.

Jede Hilfe auf diesem würde geschätzt.

War es hilfreich?

Lösung

Da vector<bool> in STL spezialisiert und erfüllt nicht tatsächlich die Anforderungen eines Standardcontainers.

Herb Sutter spricht darüber mehr in einem GOTW Artikel: http://www.gotw.ca /gotw/050.htm

Andere Tipps

Ein vector<bool> ist kein echter Behälter. Ihr Code versucht effektiv einen Verweis auf ein einzelnes Bit zurück, was nicht erlaubt ist. Wenn Sie Ihren Behälter zu einem deque ändern, ich glaube, Sie werden das Verhalten erhalten Sie erwarten.

Ein vector<bool> ist wie alle anderen Vektoren nicht implementiert und funktioniert nicht wie sie auch nicht. Sie sind besser dran, einfach nicht verwenden, und nicht besorgniserregend, wenn Ihr Code seine viele Besonderheiten nicht umgehen kann -. Es meist um eine schlechte Sache, die wir von einigen unthinking C ++ Standard-Ausschussmitgliedern aufgezwungen betrachtet

Einige kleinere Änderungen an Ihrer Klasse sollte es beheben.

template <class T>
class MyClass
{ 
    private:
        vector<T> _items;

    public:

        // This works better if you pass by const reference.
        // This allows the compiler to form temorary objects and pass them to the method.
        void add(T const& item)
        {
            _items.push_back(item);
        }

        // For the const version of operator[] you were returning by value.
        // Normally I would have returned by const ref.

        // In normal situations the result of operator[] is T& or T const&
        // But in the case of vector<bool> it is special 
        // (because apparently we want to pack a bool vector)

        // But technically the return type from vector is `reference` (not T&) 
        // so it you use that it should compensate for the odd behavior of vector<bool>
        // Of course const version is `const_reference`

        typename vector<T>::const_reference operator[](int idx) const
        {
            return _items[idx];
        }

        typename vector<T>::reference operator[](int idx)
        {
            return _items[idx];
        }
};  

Wie die anderen Antworten weisen darauf hin, eine Spezialisierung für die Raumzuweisung im Fall von Vektor zu optimieren bereitgestellt .

Jedoch Sie noch Ihren Code gültig machen können, wenn Sie die Verwendung von Vektor :: Referenz anstelle von T machen &. In der Tat ist es eine gute Praxis Verwendung Behälter :: Referenz, wenn Daten gehalten durch einen STL-Container verweist.

T& operator[](int idx)

wird

typename vector<T>::reference operator[](int idx)

Natürlich Ther auch ein typedef für konstante Referenz ist:

const T operator[](int idx) const

und dies wird (Entfernen der nutzlose zusätzliche Kopie)

typename vector<T>::const_reference operator[](int idx) const

Der Grund für den Fehler ist, dass vector<bool> ist darauf spezialisiert, die Boolesche Werte innerhalb und vector<bool>::operator[] Renditen von Proxy eine Art gespeichert zu packen, dass Sie den Wert zugreifen kann.

Ich glaube nicht, eine Lösung wäre, den gleichen Typen wie vector<bool>::operator[] zurückkehrt, weil dann würden Sie nur über das bedauerliche besondere Verhalten zu Ihrem Container zu kopieren sein.

Wenn Sie mit vector als den zugrunde liegenden Typ behalten wollen, glaube ich, das Bool Problem durch die Verwendung eines vector<MyBool> statt geflickt werden kann, wenn MyClass mit bool instanziiert wird.

Es könnte wie folgt aussehen:

#include <string>
#include <vector>
using namespace std;

namespace detail
{
    struct FixForBool
    {
        bool value;
        FixForBool(bool b): value(b) {}
        operator bool&() { return value; }
        operator const bool& () const { return value; }
    };

    template <class T>
    struct FixForValueTypeSelection
    {
        typedef T type;
    };

    template <>
    struct FixForValueTypeSelection<bool>
    {
        typedef FixForBool type;
    };

}

template <class T>
class MyClass
{
    private:
        vector<typename detail::FixForValueTypeSelection<T>::type> _items;

    public:

        void add(T item)
        {
            _items.push_back(item);
        }

        const T operator[](int idx) const
        {
            return _items[idx];
        }

        T& operator[](int idx)
        {
            return _items[idx];
        }

};


int main(int argc, char** argv)
{
    MyClass<string> Test1;      //  Works
    Test1.add("hi");
    Test1.add("how are");
    Test1[1] = "you?";


    MyClass<int> Test2;         //  Also works
    Test2.add(1);
    Test2.add(2);
    Test2[1] = 3;


    MyClass<bool> Test3;        // Works up until...
    Test3.add(true);
    Test3.add(true);
    Test3[1] = false;           // ...this point. :(

    return 0;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top