C++ 中模板类的重载 [] 运算符具有常量/非常量版本

发布于 2024-09-13 11:40:02 字数 1352 浏览 8 评论 0原文

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

这是我的问题。我有一个 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 之外的所有数据类型。

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

Whew, that was a long title.

Here's my problem. I've got a template class in C++ and I'm overloading the [] operator. I have both a const and a non-const version, with the non-const version returning by reference so that items in the class can be changed as so:

myobject[1] = myvalue;

This all works until I use a boolean as the template parameter. Here's a full example that shows the error:

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

The error is a compiler error and the message is:

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

I've read up and found that STL uses some temporary data types, but I don't understand why it works with everything except a bool.

Any help on this would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

情未る 2024-09-20 11:40:02

因为vector是专门针对STL的,实际上并不能满足标准容器的要求。

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

Because vector<bool> is specialized in STL, and does not actually meet the requirements of a standard container.

Herb Sutter talks about it more in a GOTW article: http://www.gotw.ca/gotw/050.htm

中性美 2024-09-20 11:40:02

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

A vector<bool> is not a real container. Your code is effectively trying to return a reference to a single bit, which is not allowed. If you change your container to a deque, I believe you'll get the behavior you expect.

撩动你心 2024-09-20 11:40:02

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

A vector<bool> is not implemented like all other vectors, and does not work like them either. You are better off simply not using it, and not worrying if your code can't handle its many peculiarities - it is mostly considered to be A Bad Thing, foisted on us by some unthinking C++ Standard committee members.

隱形的亼 2024-09-20 11:40:02

对你的班级进行一些简单的更改应该可以解决这个问题。

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

Some monor changes to your class should fix it.

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];
        }
};  
∞琼窗梦回ˉ 2024-09-20 11:40:02

正如其他答案指出的那样,提供了专门化来优化向量<向量的情况下的空间分配。布尔>。

但是,如果您使用 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

As the other answers point out, a specialization is provided to optimize for space allocation in the case of vector< bool>.

However you can still make your code valid if you make use of vector::reference instead of T&. In fact it is a good practice to use container::reference when referencing data held by a STL container.

T& operator[](int idx)

becomes

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

Of course ther is also a typedef for const reference:

const T operator[](int idx) const

and this one becomes (removing the useless extra copy)

typename vector<T>::const_reference operator[](int idx) const
人生戏 2024-09-20 11:40:02

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

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

如果您想继续使用 vector 作为基础类型,我相信 bool 问题可以通过使用 vector 来解决,而不是在 MyClass 时使用code> 使用 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;
}

The reason for the error is that vector<bool> is specialized to pack the boolean values stored within and vector<bool>::operator[] returns some sort of proxy that lets you access the value.

I don't think a solution would be to return the same type as vector<bool>::operator[] because then you'd be just copying over the regrettable special behavior to your container.

If you want to keep using vector as the underlying type, I believe the bool problem could be patched up by using a vector<MyBool> instead when MyClass is instantiated with bool.

It might look like this:

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文