Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error: cannot bind non-const lvalue reference of type ‘bool&’ to an rvalue of type ‘bool’

Tags:

I'm creating my own Matrix Class. When it comes to the "at" function used to change the value of a certain element, I have this.

T & at(unsigned int raw, unsigned int col)
{
    return (_matrix.at(index(raw, col)));
}

knowing that

std::vector<T>  _matrix;

It works perfectly for all types expect for booleans. I'm not able to do this operation.

matrix.at(1, 1) = true;

Which is weird because I have the same implementation as std::vector "at" function, which works with booleans.

Any ideas ? Thanks.

like image 697
adrien bedel Avatar asked Apr 11 '20 13:04

adrien bedel


1 Answers

std::vector<bool> is special from all other std::vector specializations.

Its .at member function does not return a reference to bool, but a proxy object that can be assigned to and converted to bool. Neither the proxy object, nor the converted bool (which is a prvalue) can be bound to a bool& as you try to do in the return statement.

You must handle the case T = bool in a special way, e.g. by forbidding it for your matrix class or by using std::vector<char> instead of std::vector<bool> when your T is bool:

using U = std::conditional_t<std::is_same_v<T, bool>, char, T>;

std::vector<U>  _matrix;

and then return U& instead of T& wherever you return references. (This requires #include<type_traits> and C++17 in this form, but can be adapted to C++11.)

or by using a wrapper around bool, such as

struct A {
    bool b;
};

that you store in the vector instead of bool, so that you can still return references to the bool member properly,

or, if you intend to use the packed storage mechanism which differentiates std::vector<bool> from all other std::vector specializations, you can return the proxy object from your .at method and basically introduce the same special case that std::vector has for your matrix class, but then you will need to take care of the special case everywhere in your matrix class:

decltype(auto) at(unsigned int raw, unsigned int col)
{
    return _matrix.at(index(raw, col));
}

(removing the parentheses in the return statement is important in this case and requires C++14) or

std::vector<T>::reference at(unsigned int raw, unsigned int col)
{
    return _matrix.at(index(raw, col));
}

It is very unfortunate that std::vector<bool> is special in that way. Read more about this e.g. in this question and on the cppreference.com page for std::vector<bool>.

like image 52
walnut Avatar answered Sep 21 '22 22:09

walnut