10

I have the following code snippet, which takes the std::vector<int> list and writes a zero in all vector elements. This example is working perfectly fine.

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

If I take change the type of the vector from int to bool, the code will not compile.

#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

I don't understand the compiler error message:

/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: error: no matching function for call to object of type '(lambda at :7:18)'

    __f(*__first);

    ^~~

:10:10: note: in instantiation of function template specialization 'std::for_each:7:18)>' requested here

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

     ^

:7:18: note: candidate function not viable: no known conversion from 'std::_Bit_iterator::reference' (aka 'std::_Bit_reference') to 'bool &' for 1st argument

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

             ^

:7:18: note: conversion candidate of type 'void (*)(bool &)'

Why does std::foreach work with a std::vector<int>, but does not work with a std::vector<bool>?

Is the memory optimisation of an std::vector<bool> (see here ) part of the answer?

Boann
  • 48,794
  • 16
  • 117
  • 146
schorsch312
  • 5,553
  • 5
  • 28
  • 57
  • 5
    Iterator type of `std::vector` doesn't return `bool&` on dereference. Rather, it returns a proxy object. Use `auto&` instead of `bool&` to get the proxy. – Incomputable May 29 '18 at 11:08
  • 6
    @Incomputable: Please don't put answers in the comments section. – andreee May 29 '18 at 11:11

1 Answers1

22

Reason

The problem stems from the fact that dereferencing an iterator that came from std::vector<bool> doesn't return bool&, but rather a proxy object. Thus, it is not regarded as stl container (thanks to @KillzoneKid).

Fix

Use auto element in the parameter list. In general, if you don't care about the type, use auto&& in the lambda parameter list.

#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.

Trying to use auto& will trigger compilation error again, as the proxy returned is not lvalue, but rvalue. Thus, auto&& has even more benefits than usual.

Incomputable
  • 2,188
  • 1
  • 20
  • 40