[英]Overloaded [] operator on template class in C++ with const / nonconst versions
Whew, that was a long title. 哇,这是一个很长的头衔。
Here's my problem. 这是我的问题。 I've got a template class in C++ and I'm overloading the [] operator.
我在C ++中有一个模板类,我正在重载[]运算符。 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:
我有一个const和一个非const版本,非const版本通过引用返回,以便类中的项可以更改为:
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. 我已经阅读并发现STL使用了一些临时数据类型,但我不明白为什么它适用于除bool之外的所有内容。
Any help on this would be appreciated. 任何有关这方面的帮助将不胜感激。
Because vector<bool>
is specialized in STL, and does not actually meet the requirements of a standard container. 因为
vector<bool>
专门用于STL,并且实际上不符合标准容器的要求。
Herb Sutter talks about it more in a GOTW article: http://www.gotw.ca/gotw/050.htm Herb Sutter在GOTW文章中更多地讨论了它: http : //www.gotw.ca/gotw/050.htm
A vector<bool>
is not a real container. vector<bool>
不是真正的容器。 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. 如果您将容器更改为
deque
,我相信您会得到您期望的行为。
A vector<bool>
is not implemented like all other vectors, and does not work like them either. vector<bool>
并不像所有其他向量一样实现,也不像它们那样工作。 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. 你最好不要使用它,不要担心你的代码是否无法处理它的许多特性 - 它主要被认为是一件坏事,一些不假思索的C ++标准委员会成员强加给我们。
Some monor changes to your class should fix it. 你班上的一些monor改变应该修复它。
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];
}
};
As the other answers point out, a specialization is provided to optimize for space allocation in the case of vector< bool>. 正如其他答案所指出的那样,在vector <bool>的情况下,提供了一种专门化来优化空间分配。
However you can still make your code valid if you make use of vector::reference instead of T&. 但是,如果使用vector :: reference而不是T&,您仍然可以使代码有效。 In fact it is a good practice to use container::reference when referencing data held by a STL container.
事实上,在引用STL容器持有的数据时使用container :: reference是一个好习惯。
T& operator[](int idx)
becomes 变
typename vector<T>::reference operator[](int idx)
Of course ther is also a typedef for const reference: 当然,ther也是const参考的typedef:
const T operator[](int idx) const
and this one becomes (removing the useless extra copy) 而这一个成为(删除无用的额外副本)
typename vector<T>::const_reference operator[](int idx) const
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. 出错的原因是
vector<bool>
专门用于打包存储在其中的布尔值,而vector<bool>::operator[]
返回某种允许您访问该值的代理。
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. 我不认为解决方案是返回与
vector<bool>::operator[]
相同的类型,因为那时你只是将令人遗憾的特殊行为复制到容器中。
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
. 如果你想继续使用
vector
作为底层类型,我相信当使用bool
实例化MyClass
时,可以通过使用vector<MyBool>
来修补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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.