I wanted to make a Table class that is supposed to work like a table with columns and rows, and values in the cells. Obviously I need a function that would allow to get the value from a particular cell. I wanted this function (operator() in my case) to return a reference, so that it would be easy to change the cell's contents.
Now, I wanted to check in this function whether or not such a cell exists (i.e. are there enough columns and rows in the table). The problem is, I can't just return something like a nullptr if col/row index is out of bounds in a function that returns a reference.
I've read some other topics on SO and people suggested using optional<reference_wrapper>. Now, the problem is, I can't assign anything to the returned value. Here's the code:
class Table {
public:
class Column {
public:
std::string Header;
int Index = 0;
std::vector<std::string> colCells;
Column(std::string colHeader) { Header = colHeader; }
};
std::vector<Column> Columns;
std::optional<std::reference_wrapper<std::string>> operator()(int col, int row) {
return Columns[col].colCells[row];
}
void AddColumn(std::string colHeader) {
Column col(colHeader);
col.Index = Columns.size();
Columns.push_back(col);
for (auto& row : Columns[0].colCells) { //for each row in the first column (we created a column first, so there's at least this one)
col.colCells.push_back(""); //create a cell with an empty string
}
}
void AddRow() {
for (auto& col : Columns) {
col.colCells.push_back(""); //add empty string at the end of each column
}
}
};
AddColumn and AddRow methods aren't important here, I guess, but I just pasted them here for the code to be complete. Now, I tried this:
data::tbl(4, 0) = "Col: 2, Row: 0";
And that's the errors I get. It seems as if this wasn't an actual reference to the cell's data. I should add that everything works fine the same way if I don't use optional and have the operator

What is happening and why?
PS. I know that another way to do all that, would be to change the return value to a pointer. But then I would have to dereference the returned pointer everywhere in the code like this:
*data::tbl(4, 0) = "Col: 2, Row: 0";
Which is something I'd rather avoid if possible.
std::optionalalso has to be dereferenced. It cannot provide direct access to underlying object, since it may benullopt(like pointer can benullptr).(*data::tbl)(4, 0). But that doesn't solve your main problem, this is no different than returning a pointer and suffers from the same problem of potentially dereferencing null.nullptr, so you're adding all that extra work to create a reference with a bool to indicate whether it's even a valid reference. Really, if you need a "doesn't exist" result, a pointer will do just fine. Another alternative, especially if this is just meant to be an error-checking mechanic, is to return a reference or throw an error.std::reference_wrapper>, why does it even exists? Isn't it always better (I mean, simpler - you don't need to#include <optional>) to just use pointers then?