Pergunta

Ufa, que foi um título longo.

Aqui está o meu problema.Eu tenho um modelo de classes em C++ e estou sobrecarregar o [] operador.Eu tenho um constante e uma não-const versão, com o não-const versão voltar de referência, de modo que os itens da classe pode ser alterada assim:

myobject[1] = myvalue;

Tudo isso funciona até usar um booleano, como o parâmetro do modelo.Aqui está um exemplo completo que mostra o erro:

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

O erro é um erro de compilador e a mensagem é:

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

Eu já leu e descobriu que STL usa temporários, tipos de dados, mas eu não entendo por que ele funciona com tudo, exceto um bool.

Qualquer ajuda sobre este seria apreciada.

Foi útil?

Solução

Porque vector<bool> é especializado em STL e na verdade não atende aos requisitos de um contêiner padrão.

Herb Sutter fala mais sobre isso em um artigo GOTW: http://www.gotw.ca/gotw/050.htm

Outras dicas

UMA vector<bool> não é um recipiente real. Seu código está efetivamente tentando retornar uma referência a um único bit, o que não é permitido. Se você mudar seu contêiner para um deque, Acredito que você terá o comportamento que espera.

Um vector<bool> não é implementada como todos os outros vetores, e não funciona como eles.É melhor que você simplesmente não o estiver usando, e não se preocupar se o seu código não pode lidar com suas muitas peculiaridades - é principalmente considerado Uma Coisa Ruim, que nos foi impingida por alguns irreflectido, C++ Padrão membros do comitê.

Algumas mudanças de monor na sua classe devem corrigi -la.

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

Como as outras respostas apontam, é fornecida uma especialização para otimizar a alocação de espaço no caso do Vector <BOOL>.

No entanto, você ainda pode tornar seu código válido se usar o Vector :: Referência em vez de T &. De fato, é uma boa prática usar o contêiner :: Referência ao referenciar dados mantidos por um contêiner STL.

T& operator[](int idx)

torna-se

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

Claro que também é um typedef para const const:

const T operator[](int idx) const

e este se torna (removendo a cópia extra inútil)

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

O motivo do erro é que vector<bool> é especializado para embalar os valores booleanos armazenados dentro e vector<bool>::operator[] Retorna algum tipo de proxy que permite acessar o valor.

Eu não acho que uma solução seria retornar o mesmo tipo que vector<bool>::operator[] Porque então você estaria apenas copiando o comportamento especial lamentável do seu contêiner.

Se você quiser continuar usando vector Como tipo subjacente, acredito que o problema do bool pode ser corrigido usando um vector<MyBool> Em vez disso, quando MyClass é instanciado com bool.

Pode ser assim:

#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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top