6

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.

adrien bedel
  • 116
  • 8

1 Answers1

6

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

walnut
  • 21,629
  • 4
  • 23
  • 59