Consider the following class Foo
which provides 2 operators ()
, one for reading and another one for writing.
#include <iostream>
#include <vector>
template <typename T>
class Foo {
public:
Foo(const std::vector<T> &values) { vals = values; }
const T &operator()(const int i, const int j) const {
std::cout << "Read" << std::endl;
return vals[i];
}
T &operator()(const int i, const int j) {
std::cout << "Write" << std::endl;
return vals[i];
}
private:
std::vector<T> vals;
};
int main() {
std::vector<int> values(100, 1);
Foo<int> f{values};
f(1,1) = 42; //here it writes:OK
std::cout << f(1,1) << std::endl; //why is again the "read" version called?
return 0;
}
I am not able to understand why only the "write" version is called in my code.
The problem is that f
is non-const, which means that the non-const member function version is a better match than the const member function version since the type of this
parameter for non-const version is Foo<int>*
while for the const version it is const Foo<int>*
and so the latter requires a qualification conversion while the former does not and hence a better match.
To solve this you can either make f
const(but then you won't be able to write on it) or use const_cast
on the non-const f
as shown below:
int main()
{
std::vector<int> values(100, 1);
Foo<int> f{values}; //non-const f
f(1,1) = 42; //uses write version
//use read version now as we've used const_cast
std::cout << const_cast<const Foo<int>&>(f)(1, 1) << '\n'; //use const_cast
return 0;
}
With C++17 you can also use std::as_const
as shown in this demo.