【问题标题】:Why vector<bool>::reference doesn't return reference to bool?为什么 vector<bool>::reference 不返回对 bool 的引用?
【发布时间】:2012-01-14 00:37:15
【问题描述】:
#include <vector>

struct A
{
    void foo(){}
};

template< typename T >
void callIfToggled( bool v1, bool &v2, T & t )
{
    if ( v1 != v2 )
    {
        v2 = v1;
        t.foo();
    }
}

int main()
{
    std::vector< bool > v= { false, true, false };

    const bool f = false;
    A a;

    callIfToggled( f, v[0], a );
    callIfToggled( f, v[1], a );
    callIfToggled( f, v[2], a );
}

上面例子的编译产生下一个错误:

dk2.cpp: In function 'int main()':
dk2.cpp:29:28: error: no matching function for call to 'callIfToggled(const bool&, std::vector<bool>::reference, A&)'
dk2.cpp:29:28: note: candidate is:
dk2.cpp:13:6: note: template<class T> void callIfToggled(bool, bool&, T&)

我使用 g++(4.6.1 版)编译如下:

g++ -O3 -std=c++0x -Wall -Wextra -pedantic dk2.cpp

问题是为什么会发生这种情况? vector&lt;bool&gt;::reference 不是 bool&amp;?还是编译器的错误?
或者,我在尝试一些愚蠢的事情吗? :)

【问题讨论】:

  • 不幸的是,尽管有它的名字,std::vector&lt;bool&gt; 并不是boolvector
  • 作为一种解决方法,您可以使用std::unique_ptr&lt;bool[]&gt;(new bool[3])...
  • Herb Sutter 的When Is a Container Not a Container? 就是关于这个问题的。
  • Howard Hinnant 的文章 On vector<bool> 说这是一个很好的优化,只是名称应该被更改为不表示标准容器的更大含义。

标签: c++ compiler-errors g++


【解决方案1】:

Vector is specialized for bool.

这被认为是标准错误。请改用vector&lt;char&gt;

template<typename t>
struct foo {
  using type = t;
};
template<>
struct foo<bool> {
  using type = char;
};

template<typename t, typename... p>
using fixed_vector = std::vector<typename foo<t>::type, p...>;

有时您可能需要引用向量中包含的布尔值。不幸的是,使用vector&lt;char&gt; 只能为您提供对字符的引用。如果您真的需要bool&amp;,请查看Boost Containers library。它有一个非专用版本的vector&lt;bool&gt;

【讨论】:

  • 不错的解决方法,以及用于别名的新 using 语法的不错演示。
  • @Nawaz 我向上帝发誓这是双关语。
【解决方案2】:

您的期望是正常的,但问题是std::vector&lt;bool&gt; 是 C++ 委员会的一种实验。它实际上是一个模板特化,将 bool 值紧密地存储在内存中:每个值一个位。

而且由于您无法引用位,所以这是您的问题。

【讨论】:

  • +1。 std::vector 仅支持 std::vector 提供的功能的子集。这很丑,因为您必须用不同的类型 (char) 替换 bool 才能获得工作向量。
  • 大多数(如果不是全部)委员会成员都后悔的实验!
【解决方案3】:

std::vector&lt; bool &gt; 打包其内容,因此每个布尔值都存储在一位中,八位到一个字节。这是内存效率高但计算量大的方法,因为处理器必须执行算术才能访问请求的位。而且它不适用于bool 引用或指针语义,因为字节内的位在 C++ 对象模型中没有地址。

您仍然可以声明std::vector&lt;bool&gt;::reference 类型的变量并像使用bool&amp; 一样使用它。这允许通用算法兼容。

std::vector< bool > bitvec( 22 );
std::vector< bool >::reference third = bitvec[ 2 ];
third = true; // assign value to referenced bit

在 C++11 中,您可以使用 auto&amp;&amp; 说明符解决此问题,该说明符会自动选择绑定到向量元素的左值引用或绑定到临时元素的右值引用。

std::vector< bool > bitvec( 22 );
auto &&third = bitvec[ 2 ]; // obtain a std::vector< bool >::reference
third = true; // assign value to referenced bit

【讨论】:

  • 很好的答案,尤其是提到&amp;&amp;,这对于让代理类型/迭代器有用的泛型代码至关重要。当然,它在循环中同样有效:for (auto &amp;&amp;it: bizarreContainer)
【解决方案4】:

std::vector&lt;bool&gt; 是一个不合格的容器。为优化空间,打包bools,无法提供参考。

请改用boost::dynamic_bitset

【讨论】:

  • 要获得一种引用,您需要使用运算符 [](结果是 dynamic_bitset::reference)。虽然没有迭代器。
  • -1 因为没有提到 dynamic_bitset 的不同或更好。当然它也不能返回bool &amp;
【解决方案5】:

只要我的 2 美分:

std::vector&lt;bool&gt;::referencestruct _Bit_reference 的类型定义,定义为

typedef unsigned long _Bit_type;

struct _Bit_reference
  {
    _Bit_type * _M_p;
    _Bit_type _M_mask;

    // constructors, operators, etc...

    operator bool() const
    { return !!(*_M_p & _M_mask); }
  };

像这样更改函数,它可以工作(好吧,至少可以编译,还没有测试过):

template< typename T >
void callIfToggled( bool v1, std::vector<bool>::reference v2, T & t )
{
    bool b = v2;  
    if ( v1 != b )
    {
        v2 = v1;
        t.foo();
    }
}

编辑:我将条件从 (v1 != v2)(这不是一个好主意)更改为 (v1 != b)。

【讨论】:

  • 这不是扩展,它只是 GCC 实现 vector 特化的方式。我不知道这个标准是怎么说的。您可以自己查看:lib/gcc/mingw32/4.6.1/include/c++/bits 中的 std_bvector.h。 (您的目录树可能不同,但可能相似)
  • 当然,它适用于这个特定的案例 - 进一步说明了为什么 vector&lt;bool&gt; 是一个可怕的误称 - 因为它变得非常困难、乏味或不可能在适用于其他情况的通用代码情况下使用, 实际容器。尽管如此,我认为这里一个可用的解决方法是使用template&lt;typename B, typename T&gt; void callIfToggled(B &amp;&amp;v1, B &amp;&amp;v2, T &amp;&amp;t) 并依赖来自v2 的转换运算符——我想这是感谢转发引用的另一个原因。不过,这不能原谅错误的名字选择!
【解决方案6】:

创建一个包含bool 的结构,并使用该结构类型创建vector&lt;&gt;

试试:

vector&lt;struct sb&gt; 其中sbstruct {boolean b];

那你可以说

push_back({true})

typedef struct sbool {bool b;} boolstruct; 然后vector&lt;boolstruct&gt; bs;

【讨论】:

  • C++ 中不需要structtypedef
猜你喜欢
  • 2015-11-05
  • 2015-09-07
  • 1970-01-01
  • 2018-05-27
  • 2012-08-24
相关资源
最近更新 更多