哇,这是一个很长的头衔。
这是我的问题。我在C ++中有一个模板类,我正在重载[]运算符。我有一个const和一个非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使用了一些临时数据类型,但我不明白为什么它可以处理除了bool之外的所有内容。
对此有任何帮助将不胜感激。
答案 0 :(得分:9)
因为vector<bool>
专门用于STL,并且实际上不符合标准容器的要求。
Herb Sutter在GOTW文章中更多地谈到了它:http://www.gotw.ca/gotw/050.htm
答案 1 :(得分:6)
vector<bool>
不是真正的容器。您的代码有效地尝试返回对单个位的引用,这是不允许的。如果您将容器更改为deque
,我相信您会得到您期望的行为。
答案 2 :(得分:5)
vector<bool>
没有像所有其他向量一样实现,也不像它们那样工作。你最好不要使用它,不要担心你的代码是否能够处理它的许多特性 - 它主要被认为是一件糟糕的事情,被一些不假思索的C ++标准委员会成员强加给我们。
答案 3 :(得分: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];
}
};
答案 4 :(得分:1)
正如其他答案所指出的那样,在向量&lt;的情况下,提供了一种专门化以优化空间分配。布尔取代。
但是,如果您使用vector :: reference而不是T&amp;,您仍然可以使代码有效。事实上,在引用STL容器保存的数据时使用container :: reference是一个好习惯。
T& operator[](int idx)
成为
typename vector<T>::reference operator[](int idx)
当然,ther也是const引用的typedef:
const T operator[](int idx) const
并且这个(删除无用的额外副本)
typename vector<T>::const_reference operator[](int idx) const
答案 5 :(得分:1)
错误的原因是vector<bool>
专门用于打包存储在其中的布尔值,vector<bool>::operator[]
返回某种代理,允许您访问该值。
我认为解决方案不会返回与vector<bool>::operator[]
相同的类型,因为那时你只是将令人遗憾的特殊行为复制到容器中。
如果您希望继续使用vector
作为基础类型,我相信当使用vector<MyBool>
实例化MyClass
时,可以使用bool
修补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;
}