【问题标题】:Why `vector<bool> v; for(auto&& e:v){e=false}` compiles(i.e. the element's value could be modified) whereas the ref of vector<bool> is a prvalue?为什么 `vector<bool> v; for(auto&& e:v){e=false}` 编译(即元素的值可以修改)而vector<bool>的ref是prvalue?
【发布时间】:2020-06-10 05:56:20
【问题描述】:

为什么下面的代码可以编译(即元素的值可以修改)而vector&lt;bool&gt; 的引用是prvalue?如果能在这个问题上得到一些帮助,我将不胜感激。

下面是相关代码:

#include <vector>
#include <iostream>

int main()
{
    std::vector<bool> v(10,true);
    for (auto&& e : v)
    {
        std::cout << e << std::endl;
        e = false;  //I wonder why this expression works whereas the ref of vector<bool> is a prvalue?
    }    

    for (auto&& e : v)
    {
        std::cout << e << std::endl;  
    }    
}

【问题讨论】:

  • 你知道为什么v[0] = false; 编译吗?
  • @HolyBlackCat 如果vvector&lt;int&gt; 之类的类型,我可以理解为它们的引用是左值。但是vector&lt;bool&gt;的reference是prvalue(通过,我完全看不懂,有高手告诉我,我背了。)。我很困惑。我可以为prvalue做作业真是太神奇了!
  • 你一直在说“引用”,这通常意味着一个左值引用(使用单个 &amp;),但你拥有的是一个右值引用(双 &amp;&amp;),这使得这是一个非常不同的事情。这可能是一个需要语言律师通过参考 C++ 规范中的部分来回答的问题。
  • @Someprogrammerdude 一些专家告诉我vector&lt;bool&gt; 的引用是prvalue。虽然我完全不明白,也没有找到任何证据,但作为他们在 SO 上的高声誉,我相信他们是对的。

标签: c++ c++11


【解决方案1】:

vector&lt;bool&gt; 很特别。与其他类型的向量不同,它不存储实际的bools(这需要每个bool 使用1 个字节)。相反,它将它们作为位打包存储在一个整数数组中(每个值 1 位;例如,它可能将一个 unsigned char 数组和 8 个 bools 作为位打包到一个 unsigned char 中)。

因为vector&lt;bool&gt; 中没有实际的bools,所以您无法形成对它们的引用。所以通常会产生引用的操作(例如取消引用迭代器)不能这样做。

一些专家告诉我vector&lt;bool&gt; 的参考是prvalue。虽然我完全不明白。但作为他们对 SO 的高额奖金,我相信他们是对的。

他们的意思是取消引用 vector&lt;bool&gt; 迭代器会返回 prvalue(这只是意味着它按值而不是按引用返回)。

vector&lt;bool&gt; 的引用” 他们可能指的是vector&lt;bool&gt;::referencevector&lt;bool&gt;::const_reference,它们指的是在取消引用@987654338 的迭代器(分别为正则和常量)时获得的类型@。通常,对于vector&lt;T&gt; (T != bool),它们将分别等于T &amp;const T &amp;,但对于vector&lt;bool&gt;const_referenceboolreference 是某个类。

vector&lt;bool&gt;::reference 类具有一些重载运算符,使其 引用一样工作。特别是,它重载了operator=,因此您可以将bools 分配给它。 (它将向量的单个特定位设置为1。)

至于为什么for (auto&amp;&amp; e : v) 有效...auto &amp;&amp; 是一个转发参考。我不打算解释转发引用是如何工作的(查一下!),但你的循环相当于for (std::vector&lt;bool&gt;::reference &amp;&amp;e : v)(如果它不是bool 的向量,它会变成for (ElementType &amp;e : v))。

当您执行e = false; 时,您会调用std::vector&lt;bool&gt;::reference 的重载operator=

【讨论】:

  • TL;DR 取消引用迭代器和 std::vector&lt;bool&gt;operator[] 返回代理类 (std::vector&lt;bool&gt;::reference) 的对象,该对象具有重载赋值 operator=。这用于设置相应的内部打包向量元素。
  • @HolyBlackCat 谢谢你的澄清。我能在某种程度上理解你的意思。我对你的回答毫无疑问。我只是有点困惑。根据文档(en.cppreference.com/w/cpp/container vector_bool/reference ),它清楚地表明[强调我的]:std::vector 专业化将 std::vector::reference 定义为可公开访问的嵌套类. std::vector::reference 代理对 std::vector 中单个位的引用行为。std::vector::reference 的主要用途是提供一个左值从 operator[] 返回。
  • @John 这句话在我看来颇具误导性。 operator[]std::vector&lt;bool&gt; 按值返回 reference。它的调用表达式如何通过左值?见this relevant question。似乎这里的文档是错误的(即使 cppreference 也不完美;如果您有疑问,请查看标准 :)。
  • @John 不知道他们的意思。也许他们想说vector&lt;bool&gt;::referenceoperator[] 返回,而不是左值引用。
  • @DanielLangr 这个问题是我自己发的! :) 可惜很快就关门了。
猜你喜欢
  • 2014-09-28
  • 2015-09-07
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 2013-07-21
相关资源
最近更新 更多