呼,这是一个长标题。

下面是我的问题。我有一个在C模板类++和我超载[]操作。我同时拥有常量和非const版本,与非const版本通过引用返回所以在类的项目可以被改变为这样:

myobject[1] = myvalue;

这一切工作,直到我用一个布尔值作为模板参数。这里的一个完整的例子,显示了错误:

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

该错误是一个编译错误并且所述消息是:

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

我读的时候,发现STL使用了一些临时数据类型,但我不明白为什么它除了一个布尔一切正常。

任何帮助,将不胜感激。

有帮助吗?

解决方案

由于vector<bool>是专业STL,并且实际上不符合标准的容器的要求。

香草萨特一个GOTW文章中谈到它: http://www.gotw.ca /gotw/050.htm

其他提示

一个vector<bool>不是一个真正的容器。您的代码有效地试图引用返回单个位,这是不允许的。如果你改变你的容器一个deque,我相信你会得到你所期望的行为。

一个vector<bool>未实现像所有其他载体,并且或者不起作用像它们。你最好根本不使用它,而不是担心,如果你的代码无法处理它的许多特点 - 它主要是认为是坏事,有些没头没脑的C ++标准委员会成员强加给我们

一些小的改动你的类应该修复它。

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

作为其他的答案指出,一个专门被提供,以优化空间分配在矢量<布尔>的情况。

但是你仍然可以使你的代码有效的,如果你使用的矢量::参考,而不是T&。事实上,它是一个好的做法是使用容器::参考引用通过STL容器保持的数据时。

T& operator[](int idx)

变为

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

当然疗法也是常量引用一个的typedef:

const T operator[](int idx) const

和这一个变为(除去无用额外拷贝)

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

的原因错误是vector<bool>专门收拾存储中的布尔值和vector<bool>::operator[]回报某种代理的,可以让你访问的值。

我不认为一个解决办法是将返还相同种类的vector<bool>::operator[]因为那时你只是复制了令人遗憾的特殊行为,您的容器。

如果你想使用vector为标的的类型不断,我相信布尔问题可以通过使用vector<MyBool>代替时MyClassbool实例进行修补。

有可能是这样的:

#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;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top