C++ [] Array Operator With Multiple Arguments

C++ [] array operator with multiple arguments?

Prior to C++23, you could not overload operator[] to accept multiple arguments. As a workaround, you instead can overload operator(). (See How do I create a subscript operator for a Matrix class? from the C++ FAQ.)


From C++23, as mentioned in a (deleted) answer by cigien, multiple subscript arguments can be passed to operator[] directly. See this demo from the cppreference page.

Can C++'s operator[] take more than one argument?

Prior to C++23 it isn't possible. You can do this from C++23.

From cppreference:

Since C++23, operator[] can take more than one subscripts. For example, an operator[] of a 3D array class declared as T& operator[](std::size_t x, std::size_t y, std::size_t z); can directly access the elements.

example code from there: https://godbolt.org/z/993s5dK7z

From C++23 draft:

struct X {
Z operator[](std::initializer_list<int>);
Z operator[](auto...);
};
X x;
x[{1,2,3}] = 7; // OK, meaning x.operator[]({1,2,3})
x[1,2,3] = 7; // OK, meaning x.operator[](1,2,3)

Thus, the snippets you posted will work in C++23.

Operator overloading with multiple arguments

If you want to add two boxes, your operator+() should only add two boxes.

The expression you want to use involves two operations, addition and multiplication. So you need to implement a multiplication operator overload. After that, you just let the order of operations take over. Because you want one operand to be a double or some other number type, it can't be a member function (the first operand would always be the calling object). Here I've implemented a possible solution.

#include <iostream>

class Box {
public:
Box() = default;
Box(double len, double bread, double h)
: length(len), breadth(bread), height(h) {}
double getVolume(void) { return length * breadth * height; }
void setLength(double len) { length = len; }
void setBreadth(double bre) { breadth = bre; }
void setHeight(double hei) { height = hei; }

Box& operator+=(const Box& other) {
this->length += other.length;
this->breadth += other.breadth;
this->height += other.height;

return *this;
}

friend Box operator+(Box lhs, const Box& rhs) {
lhs += rhs;

return lhs;
}

friend Box operator*(double z, const Box& box) {
return Box(z * box.length, z * box.breadth, z * box.height);
}

friend Box operator*(const Box& box, double z) {
return z * box;
}

private:
double length = 0.0; // Length of a box
double breadth = 0.0; // Breadth of a box
double height = 0.0; // Height of a box
};

// Main function for the program
int main() {
Box Box1(6.0, 7.0, 5.0); // Declare Box1 of type Box
Box Box2(12.0, 13.0, 10.0); // Declare Box2 of type Box
Box Box3; // Declare Box3 of type Box
double volume = 0.0; // Store the volume of a box here

// volume of box 1
volume = Box1.getVolume();
std::cout << "Volume of Box1 : " << volume << '\n';

// volume of box 2
volume = Box2.getVolume();
std::cout << "Volume of Box2 : " << volume << '\n';

// Add two object as follows:
Box3 = Box1 + 1.2 * Box2; // Changed to demonstrate new operator

// volume of box 3
volume = Box3.getVolume();
std::cout << "Volume of Box3 : " << volume << '\n';

return 0;
}

I made some other changes to the code as well. I added constructors to simplify initialization. I changed the way operator+() works to better align with the recommendations in the standard (link).

The multiplication operator doesn't fit under that umbrella, since your scaling factor cannot (and should not) be implicitly convertible to a Box. It is implemented as a pair of functions to preserve the commutative property of multiplication.

c++ operator[] compiles fine with multiple arguments, is there a way to avoid that?

What you see here is the comma operator in action. The left operator is evaluated, its result is discarded and the result of the expression is the right operator.

Is there a way to avoid potential errors by a compilation error in such cases?

Well.. you could chose a custom type for the index and overload its comma operator. However, this is not recommended.

Instead, pay attention to your compiler warnings. For example gcc -Wall warns for this code:

int main(){
int x = (1,2);
}

with

<source>:4:14: warning: left operand of comma operator has no effect [-Wunused-value]

4 | int x = (1,2);

| ^

How do I use multiple arguments from an array to construct an execl() call in C?

Taken directly from "man execl"

The execv() and execvp() functions provide an array of pointers to
null-terminated strings that represent the argument list available to
the new program. The first argument, by convention, should point to
the filename associated with the file being executed. The array of
pointers must be terminated by a NULL pointer.

EDIT:
Here are the prototypes.

int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);

How to overload the operator[] with multiple subscripts

fooObject[ 0, 0, 0 ] = 5;

not

fooObject.matrix[ 0, 0, 0 ] = 5;

you should also add compile option --std=c++23.

passing multiple, comma separated, arguments to a custom operator

Either you call it explicitly:

MyClassObject.operator<<(4,100);

Or you redefine it to take only a single argument, e.g.

MyClass &operator<<(std::array<int,2> par)

or

MyClass &operator<<(std::pair<int,int> par)

and then call it

MyClassObject << {4,100};

C++ multidimensional array operator

Nope, that is not possible. There are two alternatives, though:

You can have operator[] return an array of a smaller dimension (For a 3D array, it will return a 2D array, for a 2D array it will return a 1D array, and for a 1D array, it will return a single element). Then you can "string them together" with the syntax you want. (arr[x][y][z])

Alternatively, you can overload operator(), because that can take multiple arguments.

Then you can use it like this, to index into a 3D array for example: arr(x,y,z)

But you can't overload [][] or [][][] as a single operator.

With several uses of [x, y, z, ...]-clause syntax, shouldn't operator[] be allowed to accept multiple parameters?

It's certainly an option, although surprising to many, given the general tendency to stick to C syntax for operators familiar to C programmers.

It's also not a new idea, Gabriel Dos Reis suggested it in 2014. The last-documented state of the idea from Uniform handling of operator[] and operator() is follows:

In c++std-core-14770, Dos Reis suggests that operator[] and operator() should both be allowed to be static. In addition to that, he suggests that both should allow multiple parameters. It's well known that there's a possibility that this breaks existing code (foo[1,2] is valid, the thing in brackets is a comma-expression) but there are possibilities to fix such cases (by requiring parens if a comma-expression is desired). EWG should discuss whether such unification is to be strived for.

Discussed in Rapperswil 2014. EWG points out that there are more issues to consider here, in terms of other operators, motivations, connections with captureless lambdas, who knows what else, so an analysis paper is requested.

So to paraphrase that eminent C++ language theorist: If you like it then write a paper on it.



Related Topics



Leave a reply



Submit