2

I'm creating a custom double list class. I'd like to overload the () operator so that I can both access elements and assign values to list elements. These functions appear with return types, double and double &, below, respectively in list.h. However, you can see below when I run main.cpp, attempting to use both, only the second operator() is called. I am obviously misunderstanding something -- what is incorrect in my current code, and why is it incorrect?

list.h

#include <iostream>

class list {
    public:
        // Constructor
        list(int length);
        // Destructor
        ~list();
        // Element accessors
        double operator()(int i) const;
        double & operator()(int i);
    private:
        int length;
        double * data;
};

list::list(int length) {
    this->length = length;
    this->data   = new double[length];
}

list::~list() { delete [] this->data; }

double list::operator()(int i) const {
    std::cout << "()1" << std::endl;
    return this->data[i];
}

double & list::operator()(int i) {
    std::cout << "()2" << std::endl;
    return this->data[i];
}

main.cpp

#include <iostream>
#include "list.h"
using namespace std;

int main() {
    list l(3);
    double x;

    // Assign to list element. Should print "()2".
    l(1) = 3;
    // Get list element value. Should print "()1".
    x = l(1);

    return 0;
}

After compilation, the program prints:

()2
()2

Edit

My problem arose due to the order in which I added the two functions, and some misunderstanding on my part. I first wrote a simple accessor, i.e.:

double list::operator()(int i);

Afterwards, I tried to add a "setter" overload:

double & list::operator()(int i);

At this point the compiler complained. I searched the web, and without really understanding, added a const keyword after the first function. This stopped the compiler complaints, but then led to the question above. My solution is to eliminate the first overload, i.e., remove:

double operator()(int i) const;
Matt Hancock
  • 3,870
  • 4
  • 30
  • 44
  • 3
    The function call operator () seems like the wrong operator to use here. Why not overload the selection operator [] instead? – templatetypedef May 28 '16 at 00:55
  • 1
    Because I would like to write a Matrix class, which will then require the () operator. I'm starting with the simple case first. – Matt Hancock May 28 '16 at 01:01
  • 2
    I would argue that that would not be a good design for the matrix class either. You may want to look into [proxy classes as a technique for overloading multidimensional selection](http://stackoverflow.com/questions/994488/what-is-proxy-class-in-c). It's a cool trick! – templatetypedef May 28 '16 at 01:08
  • Thanks I will look at that. – Matt Hancock May 28 '16 at 01:19

1 Answers1

2
list l(3);

This is a non-const instance of the list class. When calling the operator() function the non-const overload will be used.

const_cast<const list&>(l)(3); // Explicitly call the const overload
James Adkison
  • 9,412
  • 2
  • 29
  • 43
  • Thanks, but I simply want to be able to call the "getter" on non-const members without having to cast. However, if I remove the `const` from after the first `operator()` definition, I get errors because then it tries to use the first `operator()` instance in both cases (`error: lvalue required ...`). – Matt Hancock May 28 '16 at 01:07
  • @ChesterVonWinchester You can't do that. The function is chosen based on the type of the object you're using, not based on what you do with the result of calling the function. – molbdnilo May 28 '16 at 01:11
  • @ChesterVonWinchester It will use it when necessary. For example, if you pass the list to a function which accepts a `const list& myList`. Then `myList(3);` will call the const overload. I was just showing how explicitly making it const would call the correct overload. – James Adkison May 28 '16 at 01:16
  • Ok. So, I am a little confused. [A library like Eigen seems to accomplish exactly this](https://eigen.tuxfamily.org/dox/GettingStarted.html) (see "simple first program"). You're both saying that the way the accomplish this is not through operator overloading (because it's not possible to do it that way)? – Matt Hancock May 28 '16 at 01:22
  • @ChesterVonWinchester I'm not saying to not use operator overloading. I'm just explaining way the non-const version was called. Here is a [simplified example](http://ideone.com/JouFig) I hope help illustrate things. Why do you think that example is using the const overload? – James Adkison May 28 '16 at 01:34
  • I see. This clears it up for me, mostly; I'll explain above in an edit. – Matt Hancock May 28 '16 at 01:59