Constructing result in operator vs operating on default-constructed object - c++

I have a class which is essentially an array with labelled contents, and I'd like to define some operators for it. I'd like to do it in such a way that changing the number of elements in the class is easy, as I expect future users will change the variables tracked, but I'd also like to ensure that basic arithmetic operations on the class are as efficient as possible.
I can see two way of implementing the operators. Taking the example of a Vector2D class:
struct Vector2D {
//members
const static int nElem = 2;
double x;
double y;
//Constructors
Vector2D() {}
Vector2D(double X, double Y) : x(X), y(Y) {}
//Operators
double& operator[] (int index) {
switch(index) {
case 0:
return x;
case 1:
return y;
default:
return std::out_of_range ("Oops");
}
}
// Option 1: operator+ by constructing result
Vector2D operator+ (const Vector2D & rhs) const {
return Vector2D(x + rhs.x, y+rhs.y);
}
// Option 2: operator+ using loop and [] operator
Vector2D operator+ (const Vector2D & rhs) const {
Vector2D result;
for(int i = 0; i < nElem; i++)
result[i] = (*this)[i] + rhs[i];
return result;
}
};
Assuming I use -03 optimization, will there be any difference between the two implementations of operator+? My understanding is that since the default Vector2D constructor has no code body and the class contents are a default data type, there is no extra overhead in Option 2 for calling the default constructor on result before setting its members. I expect the two to be equivalent, but I'm not confident enough in my knowledge to be sure.

Your method won't work at all. If you want someone to be able to change nElem you can't use x, y as your names. Why? Because changing nElem to 3 won't magically add z. And since you can't do a for loop over x and y, your definition of nElem is meaningless.
Finally, this is a textbook case for the use of a number template. Create a vector which is templated over how many elements it has.
Do something like this:
template<unsigned int LEN>
class Vector{
double v[LEN];
public:
Vector operator+(const Vector &o){
Vector res;
for (unsigned int i=0;i<LEN;++i) // with -O3 and small LEN this will be unrolled
res.v[i]=v[i]+o.v[i];
}
// ... etc.
};
Then you use it like this:
Vector<2> my_2d_vec;
Vector<3> my_3d_vec;

Related

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.

How to access to subsequence of a valarray considering it as a 2D matrix in C++

I'm learning C++, so please be patient with me.
I have a std::valarray in which there are double elements and I consider it as a 2D matrix.
class Matrix {
valarray<double> elems;
int r, c;
public:
/* type? operator[](int r) { return ? } */
//...
}
I want to overload the operator[], so that I can get a row of the matrix, and after that, I want have the m[r][c] access operator.
Is there any way to get a row, as a sequence of double using std::slice in the valarray, so that if I change a value, it is changed also in the matrix?
I've read this definition in valarray:
std::slice_array<T> operator[]( std::slice slicearr );
My operator[] must have std::slice_array<double>& as returned type?
Thanks.
I don't think std::slice and std::slice_array is what you're looking for, especially the latter is nothing but a helper type with a very limited public interface. You can instead return an proxy object. Here's a possible example of how to implement that.
class Matrix {
/* ... */
class RowProxy {
public:
RowProxy(std::valarray<double>& elems, int c, int row) :
elems(elems), c(c), row(row) {}
double& operator[](int j)
{
return elems[row*c + j];
}
private:
std::valarray<double>& elems;
int row;
int c;
};
RowProxy operator[](int i)
{
return RowProxy(elems, c, i);
}
};
This way, you can access the data with two operator[].
Matrix m(2, 4); // Assuming the ctor initializes elemens with row*column
m[0][0] = 1.234;
m[1][0] = 2.234;
m[1][3] = -52.023;
Note that both Matrix and RowProxy are missing overloads and proper handling for const-ness, and variable names are poor. Also, you might want to think about an out-of-bounds error handling strategy. But it may serve as a starting point for your implementation.

Overload index operator to mimic POD multi-dimensional array?

I have an existing class, which is structured in the following way:
class Matrix
{
public:
float Data[4][4];
// ... methods
};
And subsequently used in the following ways:
Matrix m;
m.Data[0][0] = 1.0f;
float local = m.Data[0][0];
//...
I would like to replace the Data member with an overloaded indexing operator, so I can perform range checking on the indices used. While I can change the Matrix class itself, and the implementations of its member functions, I cannot modify its usages in existing code, so any solution requires that the usage syntax remains identical. It's also desirable that the solution doesn't change sizeof(Matrix). Is there a way to achieve this?
Generally for this sort of thing, you need to use a proxy class to handle the second indexing operator. It would look something like this and go in the private section of your Matrix class. I'll leave out the bounds-checking (it shouldn't be hard for you to add that yourself).
class Proxy {
Matrix& ref;
size_t i;
public:
Proxy(Matrix& on, size_t i) : ref(on), i(i) {}
float operator[] (size_t j) {
return ref.Data[i][j];
}
};
Then just have your Matrix::operator[] return an instance of this class:
Proxy operator[] (size_t i) {
return Proxy(*this, i);
}
Note that if you want a const overload (ie, you want to use the indexing operator on const Matrix objects), you'll need a separate ConstProxy class which has const Matrix& ref instead of Matrix& ref but is otherwise identical.
There is also the option of returning a reference to an array. (Note: as one of the comments pointed out, this doesn't help much with bound-checking, but I think it's interesting, so I'll leave it here.)
float (&operator[](size_t i))[4] {
return Data[i];
}
The syntax for that is quite arcane, and I believe it doesn't work in Visual Studio 2013, but you can make it a bit cleaner with a typedef.
using Proxy = float[4];
Proxy& operator[](size_t i) {
return Data[i];
}
There's one more option, if you don't mind abandoning square-bracket indexing. You can overload the function call operator like this:
float operator()(size_t i, size_t j) {
return Data[i][j];
}
Another way is define a the proxy class with the semantic of a vector
class Matrix
{
public:
struct SubMatrix
{
class Vector
{
public:
Vector(float *data) : Data(data) {}
float &operator[](int index) { return Data[index]; }
private:
float *Data;
};
Vector operator[](int index)
{
return Vector(Data[index]);
}
float Data[4][4];
};
SubMatrix Data;
// ... methods
};
Then you can use it this way:
Matrix m;
float f = m.Data[1][2];

How to recognize the assignment operator?

I've got class with overloaded [] and I need to make it to recognize, when I try to set the values to the array. I assume, that I'll have to overload the operator =, nevertheless I don't know, how shall that whole stuff look like. Part of my code:
class Matrix {
public:
Matrix(int x, int y);
~Matrix(void);
Matrix& operator =(const Matrix &matrix); //ok...this is probably wrong...
class Proxy {
public:
Proxy(double* _array) : _array(_array) {
}
double &operator[](int index) const {
return _array[index];
}
private:
double* _array;
};
Proxy operator[](int index) const {
return Proxy(_arrayofarrays[index]);
}
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
int x, y;
double** _arrayofarrays;
};
So I just need to be able to recognize when I try to set Matrix matrix(3,3); matrix[0][0]=1;
Everything else works allright, so I assumed that it's not needed to paste the whole code
It looks like you want something which is not directly possible: operator[][].
You can emulate the behavior of this by using an intermediate class:
Since a Matrix class is typically indexed as [rows][columns], you can
have the first operator method return the corresponding Row object.
The row class can than overload the operator[] and return the corresponding
element.
Row& Matrix::operator[](int r);
double& Row::operator[](int c);
Now when you create your matrix object, you can index it as expected:
Matrix matrix(3,3);
matrix[0][0] = 1;
The last line is then equivalent to calling:
matrix.operator[](0).operator[](0) = 1;
To check for out-of-bounds indices, store the matrix sizes:
Proxy operator[](int index) {
assert(index < num_rows);
return Proxy(_arrayofarrays[index]);
}
double &operator[](int index) const {
assert(index < num_cols);
return _array[index];
}
As Aldo suggeested, Proxy can be passed the array length value in it's constructor:
Proxy(double* _array, int _length) : _array(_array), num_cols(_length){
}
As a general rule of thumb, if you're passing a raw array to a function, you will almost always want to pass the length of that array as well.
Your Proxy::operator[] overload is returning a double&. This double& is the object that will eventually be assigned to by client code, and you can't intercept that (at least not easily). Probably what you need to do is to check the index parameter in your operator[] overloads, and throw your own exception there rather than passing that index along to your internal arrays.

Accessing c++ maps using a different class than the index

Suppose you have a class:
class SomeClass{
public:
int x;
SomeClass(){
x = rand();
}
bool operator<(const SomeClass& rhs) const{
return x < rhs.x;
}
};
And then you have this:
map<SomeClass, string> yeah;
Obviously this will work:
yeah[SomeClass()] = "woot";
But is there a way to get something like this:
yeah[3] = "huh";
working? I mean, I tried setting operator<(int rhs) in addition to the other operator, but no dice. Is this possible at all?
Add a constructor:
SomeClass(int y){
x = y;
}
map's [] operator only takes the templated class as its parameter. What you want instead is some way of generating a specific instance of your class that has the values you want. In this example, add a constructor that lets you specify the value x should have.
class SomeClass{
public:
int x;
SomeClass(){
x = rand();
}
SomeClass(int a) : x(a){
}
bool operator<(const SomeClass& rhs) const{
return x < rhs.x;
}
};
And then use
yeah[SomeClass(3)] = "huh";
Or you can just use
yeah[3] = "huh";
which does the same thing, calling SomeClass's constructor implicitly.
You can't use yeah[3] as this will require the map to store keys of both SomeClass and int type;
Also, consider that each time you add a new element to the map, the "indexed" position of a certain element can change, as the elements are always mainteined ordered by the key element.
If you need to look at a certain point in time for the element no j, you can use probably use an iterator on the map.