Блог пользователя Alexey

Автор Alexey, история, 7 месяцев назад, По-английски

Could anyone hint me why this code fails to compile with error?

g.cpp: In lambda function: g.cpp:66:36: error: inconsistent types ‘bool’ and ‘std::_Bit_reference’ deduced for lambda return type 66 | return was[n - 1][m - 1];

If i explicitely do

const auto bfs = [&](int del) -> bool {

it compiles ok.

code
  • Проголосовать: нравится
  • +1
  • Проголосовать: не нравится

»
7 месяцев назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Auto comment: topic has been updated by Alexey (previous revision, new revision, compare).

»
7 месяцев назад, # |
Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится

It fails due to different types of values returned from the lambda. If you specify the type explicitly, the return values are casted to it.

Note also that vector<bool>::operator [] returns proxy objects, not booleans.

»
7 месяцев назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

vector<bool> is a specialized and space-optimized version of vector class to store each value in a single bit rather than a byte. (8 bits in a byte)

So when you access a value of vector<bool>, it returns std::_Bit_reference rather than bool as you would expect.

Now, return type of lambda should be consistent in every return statement. But in your code return was[n - 1][m - 1]; has return type std::_Bit_reference and everywhere else it is bool like return false;

When you do const auto bfs = [&](int del) -> bool, you cause explicit conversion to bool and therefore it is consistent and it compiles. You could also do return bool(was[n - 1][m - 1]); and it would work.

»
7 месяцев назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

If you don't specify the return type of a lambda function, the return type in each return should be the exact same thing. For example, you can't have two returns like this:

const auto fun = [](int x) {
    if (x > 5) return 0ll;
    return 1;
};

because one returns an int and the other returns a long long. The C++ compiler doesn't care that each return type can be implicitly cast to the other. The same thing is in your code.

Actually, each bool takes up one byte, not just one bit. That's why std::vector<bool> doesn't have a bool array inside. Instead, it tries to save space by grouping many bool values into chunks, so that each byte can hold up to eight boolean values.

So, std::vector<bool> can't really return bool& because there's no bool inside the vector to return a reference to. Instead, it returns std::_Bit_reference, which has some simple logic inside that lets you modify each bit in chunks.

For a C++ compiler, std::_Bit_reference and bool aren't the same type, so you can't return both of them in different parts of your lambda function. That's why you can't compile that code without explicitly specifying that you want the lambda to return bool.