How to chain multiple operator[] - c++

I am trying to create a class that use the operator [] like
MyClass[x][y]
and it should return a value based on what I call in the function that is defined within the class. What I have so far is:
MyClass.h
class MyClass{
public:
// return one value of the matrix
friend double operator[][] (const int x, const int y);
}
I don't even think my syntax for this is right, and how can I write this function in MyClass.cpp to define what value it should return?
Like is it:
MyClass::friend double operator[][] (const int x, const int y)
{
// insert code here
}
Tried it but it keeps saying errors. I believe it is a mess up there...
Many thanks,

Overloading operator() is definitely the cleanest approach.
However, remember that this is C++, and you can bend the syntax to your will :)
In particular, if you insist on wanting to use myclass[][], you can do so by declaring an "intermediate class", here's an example:
Run It Online
#include <iostream>
using std::cout;
using std::endl;
class MyClass {
public:
using IndexType = int;
using ReturnType = double;
// intermediate structure
struct YClass {
MyClass& myclass;
IndexType x;
YClass (MyClass& c, IndexType x_) : myclass(c), x(x_) {}
ReturnType operator[](IndexType y_) { return myclass.compute(x, y_); }
};
// return an intermediate structure on which you can use opearator[]
YClass operator[](IndexType x) { return {*this, x}; }
// actual computation, called by the last "intremediate" class
ReturnType compute(IndexType x, IndexType y) {
return x * y;
}
};
int main()
{
MyClass myclass;
cout << myclass[2][3] << endl; // same as: cout << myclass.compute(2, 3) << endl;
}

You need to return a proxy object for the row. This is a very simplified example just to get you going. I have not tried compiling it.
class Matrix {
int data[4][4];
class Row {
Matrix* matrix;
int row;
int operator[](int index){
return matrix->data[row][index]; // Probably you want to check the index is in range here.
}
}
Row operator[](int row){
Row which_row;
which_row.matrix = this;
which_row.row = row; // beware that if the user passes the row around it might point to invalid memory if Matrix is deleted.
return which_row;
}
}
You could also just return the row directly from operator[] and leave the second [] to be a direct array access. IMHO it is nice with the proxy object as it can do some checking on the index and possibly have other nice member functions.

There is no operator[][]. But you can declare operator()(int, int) instead.
class Foo {
public:
double operator()(int a, int b) {
//...
}
};

If you're trying to create 4x4 Matrix class, the way I did it and the way its done in the D3DX library is to have a member variable in the class:
class Matrix
{
public:
// publicly accessible member 4x4 array
float m[4][4];
// also accessible via () operator. E.G. float value = mtx(3,2);
float operator()(int column, int row);
}

Related

Struct with array that changes dynamically

I have been looking to change dynamically the values of an array in a struct depending on other variables of the struct.
Let's say I have:
struct foo
{
int value1 = 0;
int value2 = 0;
int arr[2] = {value1, value2};
};
In the main if I have create an instance fooInstance and I want to associate a value to value1 fooInstance.value1 = 10, how can I update the value in the array ?
Thank you for your time.
Firstly, if you need an array, then I recommend storing the objects in the array directly.
I question the value (i.e. usefulness) of these aliases such as value1 when the name has no more meaning than referring to arr[i] directly. But I can see the value in case there is a descriptive name available. I'll use a more meaningful example of 2D vector with x, y dimensions. It should be easy to change float to int and change the names to match your attempt.
While Frank's solution using functions is great in most regards, it has a small caveat of having a less convenient syntax compared to variables. It's possible to achieve the variable syntax using operator overloading and anonymous unions. The trade-off is the increased boilerplate in the class definition. Example:
union Vector2 {
struct {
float a[2];
auto& operator=(float f) { a[0] = f; return *this; }
operator float&() & { return a[0]; }
operator const float&() const & { return a[0]; }
operator float () && { return a[0]; }
float* operator&() { return &a[0]; }
} x;
struct {
float a[2];
auto& operator=(float f) { a[1] = f; return *this; }
operator float&() & { return a[1]; }
operator const float&() const & { return a[1]; }
operator float () && { return a[1]; }
float* operator&() { return &a[1]; }
} y;
struct {
float a[2];
auto& operator=(float f) { a[0] = a[1] = f; return *this; }
float* begin() { return std::begin(a); }
float* end() { return std::end(a); }
} xy;
};
int main() {
Vector2 v2;
v2.xy = 1337; // assign many elements by name
v2.x = 42; // assign one element by name
std::cout << v2.x; // read one element by name
for(float f : v2.xy) { // iterate the entire array
std::cout << f;
}
}
Note to those unfamiliar with rules of unions: Reading from inactive union member is allowed only through common initial sequence of standard layout structs. This code is well defined, but the reader should be careful to not over generalise and assume that type punning through unions would be allowed; It isn't.
I adapted code from my earlier answer to another question.
It is different parameters coming from different hardwares.
This sounds like generating the accessors shown above with meta programming could be a good approach.
But, if you would like to avoid the complexity, then a more traditional approach would be to just use the array, and use enum to name the indices:
struct foo
{
int arr[100];
enum indices {
name1,
name2,
// ...
name100,
name_count,
};
};
int main()
{
foo f;
f.arr[foo.name1] = 42;
}
If at all possible, use encapsulation. That's the preferred way to create an interface/implementation skew:
struct foo
{
int& value1() { return arr_[0]; }
int& value2() { return arr_[1]; }
int* arr() { return arr_; }
private:
int arr_[2] = {0, 0};
};
void bar(foo& v) {
// access a single value
v.value1() = 3;
// access the whole array
v.arr()[0] = 5;
}
If you need access through both the individual member variables and through an array member variable, do not copy the data; rather, use the array as "the source of truth", and provide access through the individual variables or the individual member functions.
Here is your example rewritten to "alias" array variables to scalar member variables:
struct foo
{
foo() : value1(arr[0]), value2(arr[1]) {}
std::array<int,2> arr;
int& value1;
int& value2;
};
Note: this is not a good way of doing anything in production code, just an illustration of how the language lets you do something like this. Normally I would add accessor member-functions instead of member-variable references, because it avoids many problems referenced in the comments, such as breaking the value semantics.

Comparator for member variable of type std::set that requires access to other member variables

I have a class ShapeDisplay that stores a set of Rectangles. I would like to store them sorted, therefore I use a std::set. My intention is to provide a custom comparator, which compares the origin (x, y) of the rectangle to a reference point (x, y) in the display.
However, in order to achieve this, the comparator needs access to m_reference. How do I use a custom comparator, that needs access to the class members? Is my design flawed? I know there are newer ways to provide the comparator as in this link, but that doesn't solve my access issue.
Alternatively, I could just have a std::vector that I keep sorted, such that each new Rectangle is inserted in the right position. But since std::set::insert() should do that automatically with a custom comparator, I would prefer that.
Thank you.
struct Point
{
int x;
int y;
};
struct Rectangle
{
int x;
int y;
int width;
int height;
};
class ShapeDisplay
{
void insertShape(Rectangle rect)
{
m_shapes.insert(rect);
}
void setReference(Point reference)
{
m_reference = reference;
}
private:
struct CenterComparator
{
bool operator() (const Rectangle & a, const Rectangle & b) const
{
double distA = std::sqrt(std::pow(a.x - m_reference.x, 2)
+ std::pow(a.y - m_reference.y, 2));
double distB = std::sqrt(std::pow(b.x - m_reference.x, 2)
+ std::pow(b.y - m_reference.y, 2));
return distA < distB;
}
};
std::set<Rectangle, CenterComparator> m_shapes;
Point m_reference;
};
CenterComparator isn't related to ShapeDisplay, it isn't aware of its members and it isn't derived from ShapeDisplay. You need to provide CenterComparator with its own reference Point. You then need to provide an instance of CenterComparator whose reference point is set.
Note that if you change that comparator's reference point in any way you will break std::set's sorting resulting in Undefined Behavior if you try to use it. So whenever setReference is called, you need to create a new set with a new comparator and copy over the old set.
Here is your code, adapted with these changes. I assumed you meant setReference and insertShape to be part of the public interface.
#include <cmath>
#include <set>
struct Point
{
int x;
int y;
};
struct Rectangle
{
int x;
int y;
int width;
int height;
};
class ShapeDisplay
{
public:
void insertShape(Rectangle rect)
{
m_shapes.insert(rect);
}
void setReference(Point reference)
{
m_reference = reference;
// Create a comparator using this new reference
auto comparator = CenterComparator{};
comparator.reference = m_reference;
// Create a new set
auto new_shapes = std::set<Rectangle, CenterComparator>(
std::begin(m_shapes), std::end(m_shapes), // Copy these shapes
comparator); // Use this comparator
m_shapes = std::move(new_shapes);
}
private:
struct CenterComparator
{
bool operator() (const Rectangle & a, const Rectangle & b) const
{
double distA = std::sqrt(std::pow(a.x - reference.x, 2)
+ std::pow(a.y - reference.y, 2));
double distB = std::sqrt(std::pow(b.x - reference.x, 2)
+ std::pow(b.y - reference.y, 2));
return distA < distB;
}
Point reference;
};
std::set<Rectangle, CenterComparator> m_shapes;
Point m_reference;
};

C++ Can I overload the bracket [] operator to do different things if it on the LHS vs RHS of an assignment?

I am looking to accomplish the following:
int x, y, z;
foo[x] = y; acts like do_this(x,y);
z = foo[x]; acts like z = do_that(x)
I can accomplish the first with a Foo class and a Helper class, where the operator[] returns by value a Helper class constructed with x, and the operator= for the Helper class is defined to run do_this(this->x, y). Like below:
class Foo {
public:
Helper operator[](int x) {
return Helper(x);
}
};
class Helper {
public:
Helper(x) {
this->x = x;
}
void operator=(int y) {
do_this(this->x, y);
}
private:
int x;
};
What I can't figure out is how to accomplish (2). Is there a way to overload the operator[] so that it knows if it was used on the lhs vs the rhs?
Yes - give your Helper class a conversion function to int:
class Helper {
public:
Helper(x){
this->x = x;
}
Helper& operator= (int y) {
do_this(this->x, y);
return *this;
}
operator int() const {
return do_that(this->x);
}
private:
int x;
};
This will also allow other uses like product *= foo[x]; or func_taking_int(foo[x]), etc.
One potential catch is that some uses of auto or function templates would still just keep the type Helper, which might not be what's wanted - so users of Foo should still understand that this proxy sugar is going on. It could also be helpful to have some alternative syntax to explicitly get the int value for cases like that, in either Foo or Helper.
I'm not sure I've understood what you actually want to do, but you are might be able to use the const version of the operator[] vs. the non-const version. For example:
struct Foo {
Z operator [] (int x) const { // this last const is important
return do_that(x);
}
Helper operator [] (int x) {
// as you yourself have written.
}
};
There are more tips and tricks to this, for forwarding arguments perfectly (a.k.a "perfect forwarding",) for being "const correct", and many other small things, but the gist of it is the above.

C++ Overload index operator for more than one array/vector

I'm not an advanced programmer. How can I overload the [] operator for a class that has two (or more) array/vector type variables?
class X
{
protected:
std::vector<double> m_x, m_y;
public:
double& operator[](const short &i) { return ???; }
};
What should I use for ???, or how can I do it (maybe adding other definitions?) to be able to call either variable?
Additional question: will this allow other classes of type class derived : public X access m_x and m_y for writing?
UPDATE:
Thank you everyone who answered, but I'm afraid that if I draw the line then the answer to my first question is no, and to the second yes. The longer version implies either an extra struct, or class, or plain setters/getters, which I wanted to avoid by using a simple function for all.
As it stands, the current solution is a (temporary) reference to each variable, in each class to avoid the extra X:: typing (and keep code clear), since m_x would have existed, one way or another.
you can write just a function for this, like:
double &get(unsigned int whichVector, unsigned int index)
{
return (whichVector == 0 ? m_x[index] : m_y[index]);
}
or use operator():
struct A
{
std::vector<int> a1;
std::vector<int> a2;
int operator()(int vec, int index)
{
return (vec == 0 ? a1[index] : a2[index]);
}
};
A a;
auto var = a(0, 1);
but still, this is kinda strange :) probably you should just give a const ref outside, like:
const std::vector<double> &getX() const { return m_x; }
and second question: protected will be convert into private in public inheritance (child/derived will have access to these memebers)
Assuming you want m_x and m_y indexed against the same parameter and a single return value:
struct XGetter
{
double& x;
double& y;
};
XGetter operator[](const short &i) { return { m_x[i], m_y[i] }; }
And the const overload:
struct XGetterReadOnly
{
double x;
double y;
};
XGetterReadOnly operator[](const short &i) const { return { m_x[i], m_y[i] }; }
The compiler will make a good job of optimizing away the intermediate classes XGetter and XGetterReadOnly where appropriate which maybe hard to get your head round if you're a new to C++.
If using mixin doesn't make you uncomfortable you could use tag dispatching like:
#include <utility>
#include <vector>
#include <iostream>
template <size_t I>
struct IndexedVector {
std::vector<double> v;
IndexedVector():v(10){}
};
template <size_t I>
struct tag {
int i;
};
template <size_t S, class = std::make_index_sequence<S>>
struct MixinVector;
template <size_t S, size_t... Is>
struct MixinVector<S, std::index_sequence<Is...>>: IndexedVector<Is>... {
template <size_t I>
double &operator[](tag<I> i) {
return IndexedVector<I>::v[i.i];
}
};
int main() {
MixinVector<2> mv;
mv[tag<0>{0}] = 1.0;
std::cout << mv[tag<0>{0}] << std::endl;
}
To use std::index_sequence you need however compiler supporting c++14 (you could though implement it yourself in c++11). The approach is easily expandable to any number of vectors by simple MixinVector template parameter modification.
There are many broken things, either at conceptual and design level.
Are you able to point your finger simultaneously against two distinct things? No? That's why you cannot use one index to address two distinct vector retaining their distinction.
You can do many things: whatever way to "combine" two value int one is good
by a syntactic point of view:
return m_x[i]+m_y[x] or return sin(m_x[i])*cos(m_y[i]) or return whatever_complicated_expression_you_like_much
But what's the meaning of that? The point is WHY THERE ARE TWO VECTOR IN YOUR CLASS? What do you want them to represent? What do you mean (semantically) indexing them both?
Something I can do to keep their distinction is
auto operator[](int i) const
{ return std::make_pair(m_x[i],m_y[i]); }
so that you get a std::pair<double,double> whose fist and second members are m_x[i] and m_y[i] respectively.
Or ... you can return std::vector<double>{m_x[i],m_y[i]};
About your other question: Yes, inheriting as public makes the new class able to access the protected parts: that's what protected is for.
And yes, you cam R/W: public,protected and private are about visibility, not readability and writeability. That's what const is about.
But again: what does your class represent? without such information we cannot establish what make sense and what not.
Ok, stated your comment:
you need two different funcntions: one for read (double operator[](unsigned) const) and one for write (double& operator[](unsigned) const)
If you know vectors have a known length -say 200-, that you can code an idex transforamtion like i/1000 to identify the vector and i%1000 to get the index,so that 0..199 addres the first, 1000..1199 address the second 2000..2199 address the third... etc.
Or ... you can use an std::pair<unsigned,unsigend> as the index (like operator[](const std::pair<unsigned,unsigned>& i), using i.first to identify the vector, and i.second to index into it, and then call x[{1,10}], x[{3,30}] etc.
Or ... you can chain vetor together as
if(i<m_x.size()) return m_x[i]; i-=m_x:size();
if(i<m_y.size()) return m_y[i]; i-=m_y:size();
if(i<m_z.size()) return m_z[i]; i-=m_z:size();
...
so that you index them contiguously.
But you can get more algorithmic solution using an array of vectors instead of distinct vector variables
if you have std::array<std::vector<double>,N> m; instead of m_x, m_y and m_z the above code can be...
for(auto& v: m)
{
if(i<v.size()) return v[i];
i-=v.size();
}
You can return a struct has two double
struct A{
double& x;
double& y;
A(A& r) : x(r.x), y(r.y){}
A(double& x, double& y) : x(x), y(y){}
};
class X
{
protected:
std::vector<double> m_x, m_y;
public:
A operator[](const short &i) {
A result(m_x[i], m_y[i]);
return result;
}
};
Thank for editing to #marcinj

Whats the significance of return by reference?

In C++,
function() = 10;
works if the function returns a variable by reference.
What are the use cases of it?
The commonest case is to implement things like operator[].
struct A {
int data[10];
int & operator[]( int i ) {
return data[i];
}
};
Another is to return a big object from a class via an accesor function:
struct b {
SomeBigThing big;
const SomeBigThing & MyBig() const {
return big;
}
};
in order to avoid the copying overhead.
Consider the following code, MyFunction returns a pointer to an int, and you set a value to the int.
int *i;
i = MyFunction();
*i = 10;
Now shorten that to
*(MyFunction()) = 10;
It does exactly the same thing as the first code block.
You can look at a reference as just a pointer that's always dereferenced. So if my function returned a reference - not a pointer - to an int the frist code block would become
int &i;
i = MyFunction();
i = 10;
and the second would become
MyFunction() = 10;
This is what i was looking for
Getters/setters for instance
class C
{
int some_param_;
public:
int& param() { return some_param_; }
int const& param() const { return some_param_; }
};
but here you should go with some_param being a public int. Containers provide functions that return by reference, eg. vector<T>::operator[] so that you can write v[k] = x.
A very normal use case is when you write an array like class. Here you want to overload the operator [] so as you can do a[0] = 10; In that case you would want the signature to be like int& operator[](int index);
In case you have a class that contains another structure, it can be useful to directly modify the contained structure:
struct S
{
int value;
};
class C
{
public:
S& ref() { return m_s; }
private:
S m_s;
};
Allows you to write something like:
void foo()
{
C c;
// Now you can do that:
c.ref().value = 1;
}
Note: in this example it might be more straightforward to directly make m_s public rather than returning a reference.
SO screwed up my answer
You don't even need to return a reference:
struct C { };
C f() {
return C();
}
int main() {
C a;
f() = a; // compiles fine
}
Because this behavior is quite surprising, you should normally return a const value or a const reference unless the user has a sensible intent to modify the result.
It can be usefull when implementing accessors
class Matrix
{
public:
//I skip constructor, destructor etc
int & operator ()(int row, int col)
{
return m_arr[row + col * size];
}
private:
int size;
int * m_arr;
}
Matrix m(10);
m(1,0) = 10; //assign a value to row 1, col 0
Another classic case:
class Foo {
Foo();
public:
static Foo& getSingleton();
};
std::vector has operator[] which would not allow vec[n] = m otherwise.
You can also achieve method chaining (if you so desire) using return by reference.
class A
{
public:
A& method1()
{
//do something
return *this; //return ref to the current object
}
A& method2(int i);
A& method3(float f); //other bodies omitted for brevity
};
int main()
{
A aObj;
aObj.method1().method2(5).method3(0.75);
//or use it like this, if you prefer
aObj.method1()
.method2(5)
.method3(0.75);
}
The named parameter idiom is a another use case. Consider
class Foo
{
public:
Foo(
int lions,
float tigers,
double bears,
std::string zookeeper
);
};
users of this class need to remember the position of each parameter
Foo foo( 1, 2.0, 5, "Fred" );
which can be non-obvious without looking at the header. Compared to a creator class like so
class CreateFoo
{
friend class Foo;
public:
CreateFoo();
CreateFoo& lions(int lions) {
_lions = lions;
return *this;
}
CreateFoo& tigers(float tigers) {
_tigers = tigers;
return *this;
}
CreateFoo& bears(double bears) {
_bears = bears;
return *this;
}
CreateFoo& zookeeper(const std::string& zookeeper) {
_zookeeper = zookeeper;
return *this;
}
private:
int _lions;
float _tigers;
double _bears;
std::string _zookeeper;
};
which can then be used by clients like so
Foo foo = CreateFoo().
lions(1).
tigers(2.0).
zookeeper("Fred").
bears(5)
;
assuming Foo has a constructor taking a const CreateFoo&.