首页 > 解决方案 > 为什么 std::foreach 不能与 std::vector 一起使用?

问题描述

我有以下代码片段,它采用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);
}

如果我将向量的类型从 更改intbool,则代码将无法编译。

#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/../../../../include/c++/7.2.0/bits/stl_algo .h:3884:2:错误:没有匹配函数调用类型为“(lambda at :7:18)”的对象

    __f(*__first);

    ^~~

:10:10: 注意:在此处请求的函数模板特化 'std::for_each:7:18)>' 的实例化

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

     ^

:7:18: 注意:候选函数不可行:第一个参数没有从“std::_Bit_iterator::reference”(又名“std::_Bit_reference”)到“bool &”的已知转换

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

             ^

:7:18: 注意: 'void (*)(bool &)' 类型的转换候选

为什么可以std::foreach与 a 一起使用std::vector<int>,但不能与 a 一起使用std::vector<bool>

std::vector<bool>(见这里)的内存优化是答案的一部分吗?

标签: c++vectorforeachboolean

解决方案


原因

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

使固定

auto element在参数列表中使用。一般来说,如果您不关心类型,请auto&&在 lambda 参数列表中使用。

#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);

}

演示

尝试使用auto&再次触发编译错误,因为返回的代理不是左值,而是右值。因此,auto&&比平时有更多的好处。


推荐阅读