Search code examples
c++operator-overloading

Why is my class using the wrong operator()?


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.


Solution

  • 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;
    }
    

    Working demo


    With C++17 you can also use std::as_const as shown in this demo.