为什么std :: foreach不适用于std :: vector <bool>?

时间:2018-05-29 11:06:50

标签: c++ vector foreach boolean

我有以下代码片段,它接受std::vector<int> list并在所有向量元素中写入零。这个例子工作得很好。

#include <vector>
#include <iostream>
#include <algorithm>

int main () {
    std::vector<int> list {1, 1, 2};
    auto reset = [](int & element){element = 0;};

    auto print = [](int element) {std::cout << element << " ";};
    std::for_each(list.begin(), list.end(), reset);
    std::for_each(list.begin(), list.end(), print);
}

如果我将矢量类型从int更改为bool,则代码将无法编译。

#include <vector>
#include <iostream>
#include <algorithm>

int main () {
    std::vector<bool> list {true, true, false};
    auto reset = [](bool & element){element = false;};

    auto print = [](int element) {std::cout << element << " ";};
    std::for_each(list.begin(), list.end(), reset);
    std::for_each(list.begin(), list.end(), print);
}

https://godbolt.org/g/2EntgX

我不明白编译器错误消息:

  

/opt/compiler-explorer/gcc-7.2.0/lib/gcc/x86_64-linux-gnu/7.2.0 /../../../../包括/ C ++ / 7.2.0 / bits / stl_algo.h:3884:2:错误:没有匹配函数来调用类型'的对象(lambda at   :7:18)'

    __f(*__first);

    ^~~
     

:10:10:注意:在功能模板的实例化中   专业化'std :: for_each:7:18)&gt;'请求

std::for_each(list.begin(), list.end(),reset);

     ^
     

:7:18:注意:候选功能不可行:不知道   从'std :: _ Bit_iterator :: reference'转换(aka   'std :: _ Bit_reference')到'bool&amp;'第一个参数

auto reset = [](bool & element){element = false;};

             ^
     

:7:18:注意:'void(*)(bool&amp;)'的转换候选人

为什么std::foreach适用于std::vector<int>,但不适用于std::vector<bool>

std::vector<bool>(见here)部分答案的内存优化是什么?

1 个答案:

答案 0 :(得分:22)

原因

问题源于这样一个事实,即取消引用来自std::vector<bool>的迭代器并不会返回bool&,而是返回代理对象。因此,it is not regarded as stl container(感谢@KillzoneKid)。

修复

在参数列表中使用auto element。通常,如果您不关心类型,请在lambda参数列表中使用auto&&

#include <vector>
#include <iostream>
#include <algorithm>

int main () {
    std::vector<bool> list {true, true, false};
    auto reset = [](auto && element){element = false;};

    auto print = [](int element) {std::cout<< element << " ";};
    std::for_each(list.begin(), list.end(),reset);
    std::for_each(list.begin(), list.end(),print);

}

Demo

尝试使用auto&trigger compilation error again,因为返回的代理不是左值,而是右值。因此,auto&&比平时有更多的好处。