I want to implement python list in cpp, but stuck at overloading subscript operator [ ] and comma ,

167 views Asked by At

I want to implement puthon list in cpp, bug do not fin a way to implement pyton's slice operator, e.g.:

list[3:7]   // sublist including item 3 included to item 7 excluded

As colon is not an operator in cpp, we cannot overload it. So I changed my implementation to use an overloadable comma, e.g. list[3,7]. I think I first need to overload comma operator and then overload [ ] operator

But I am getting error while overloading [ ] with 2 integers:

Error is : operator[](int, int) must have exactly one argument   

Please help me solve the issue.

1

There are 1 answers

0
Christophe On

The C++ standard imposes restrictions on operator[]:

[over.sub]: operator[] shall be a non-static member function with exactly one parameter. It implements the subscripting syntax

(...) a subscripting expression x[y] is interpreted as x.operator[](y) (...)

But the single argument doesn't need to be a scalar. For example:

struct mylist {
    vector<int> oops { 3,5, 7, 9}; 
    int& operator[] (size_t i) { 
        cout << "indexing overload"<<endl; 
        return oops[i]; 
    }
    mylist operator[] (pair<int, int>p) { 
        cout << "slicing overload from "<<p.first<<" to "<<p.second<<endl; 
        return mylist();    // just for proof of concept  
    }
};

You can then use this list as explected:

mylist l; 
cout<< l[2] <<endl;  // (1) traditional indexing 
l[make_pair(3,5)];   // (2) will invoke the slice version 
l[{4,8}];            // (3) slice version as well

Online demo

However, C++ is not python, so the readers of your code will be very confused by the syntax of (2) and (3). Moreover, I'm not a python expert but I understand that slice operator can be more tricky than that, since there could be start, stop and step and any of those components can be missing.

So I'd recommend not to use a pair as an argument, but create your own slice operator parameters. You could then work on different constructors and default parameters. It could then look like:

l[myslice(3, 5)];     // myslice is a class 
l[myslice(3, 4, 2)]; 
l[mysliceto(5)];      // mysliceto could be a function returning a myslice
                      // that is constructed using a default value for start 

But since this would still be quite an unusual indexing scheme, with a view to the principle of least astonishment, I'd strongly recommend to go for the C++ usual practice and simply define the right member functions, e.g. `

l.slice(3,5); 

This will be self-documenting, without surprise, and easily digested, since it is close to well known semantics of string::substr()