10

哇,那是一个很长的标题。

这是我的问题。我在 C++ 中有一个模板类,我正在重载 [] 运算符。我有一个 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 使用了一些临时数据类型,但我不明白为什么它适用于除 bool 之外的所有内容。

对此的任何帮助将不胜感激。

4

6 回答 6

8

因为vector<bool>是专门做STL的,实际上并不符合标准容器的要求。

Herb Sutter 在 GOTW 文章中对此进行了更多讨论:http ://www.gotw.ca/gotw/050.htm

于 2010-08-11T13:40:36.107 回答
6

Avector<bool>不是真正的容器。您的代码实际上是在尝试返回对单个位的引用,这是不允许的。如果您将容器更改为 a deque,我相信您会得到您期望的行为。

于 2010-08-11T13:43:45.257 回答
5

Avector<bool>不像所有其他向量那样实现,也不像它们那样工作。你最好不要使用它,也不要担心你的代码是否无法处理它的许多特性——它通常被认为是一件坏事,被一些不加思索的 C++ 标准委员会成员强加给我们。

于 2010-08-11T13:40:20.583 回答
4

对您的课程进行一些单声道更改应该可以解决它。

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];
        }
};  
于 2010-08-11T14:08:20.533 回答
1

正如其他答案所指出的那样,在 vector< bool> 的情况下,提供了一种专门化来优化空间分配。

但是,如果您使用 vector::reference 而不是 T&,您仍然可以使您的代码有效。事实上,在引用 STL 容器保存的数据时使用 container::reference 是一种很好的做法。

T& operator[](int idx)

变成

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

当然还有一个用于 const 引用的 typedef:

const T operator[](int idx) const

而这个变成(删除无用的额外副本)

typename vector<T>::const_reference operator[](int idx) const
于 2010-08-11T14:14:58.120 回答
1

错误的原因vector<bool>是专门用于打包存储在其中的布尔值并vector<bool>::operator[]返回某种允许您访问该值的代理。

我认为解决方案不会是返回与您相同的类型,vector<bool>::operator[]因为那样您只会将令人遗憾的特殊行为复制到您的容器中。

如果您想继续使用vector作为基础类型,我相信 bool 问题可以通过使用 a来解决vector<MyBool>,而不是在MyClass使用bool.

它可能看起来像这样:

#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;
}
于 2010-08-11T15:57:45.560 回答