I was wondering about having a method return an r-value. Specifically, I was wondering if there was a way to do this with an overloaded operator.
I have this code:
struct vec4 {
float x;
float y;
float z;
float w;
...
inline float operator [] (int i)
{
switch (i) {
case 0:
return this->x;
case 1:
return this->y;
case 2:
return this->z;
case 3:
return this->w;
default:
exit(1);
return 0;
}
}
};
How can I change this so that I could use something to the effect of
vec4 v;
...
v[2] = 5.0f;
I've hear about rvalue references in C++11, and could they be a potential solution?
EDIT: I found a way to put in my actual code.
No C++11 is needed for this. Just have:
float & operator[](std::size_t i) { return data[i]; }
Now you can say v[2] = 5; and all is well.
If you wanted, you could add a constant overload that doesn't use references and which can be used for reading the value.
float operator[](std::size_t i) const { return data[i]; }
The only time you might consider rvalue member function qualifiers is if you wanted to allow assigning to a temporary member:
vec4{}[2] = 5;
In that case, you still return a lvalue reference, but you must qualify the member function:
float & operator[](std::size_t i) && { return data[i]; }
// ^^^^
You can simply use:
float& operator [] (int index)
{
return data [i];
}
This allows you to write v[2] = 5.0f; and it will work as expected. No need for r-value references here.
You should also add a const-overload to retrieve the value, like this:
float operator [] (int index) const
{
return data [i];
}
This will allow you to write code like this: const vec4 v; float x = v[1];.
For what you want to accomplish, you apparently want to return an lvalue, not an rvalue. That's actually pretty easy:
float &operator[](size_t i) { return data[i]; }
Note that when you're defining the function inside the class definition, inline is redundant -- defining the function inside the class definition makes it inline by default.
Related
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.
I have a class which has a member defined as:
float U[2][2];
Now I have an accessor function and I would like to return a reference to this array. So, I have something like:
const float & [2][2] mat() const
{
return U;
}
Is there a way to return it using this kind o syntax rather than pointer syntax (I think it makes things more explicit).
It's awkward, but:
const float (&mat() const)[2][2]
{
return U;
}
Using a typedef or decltype might be better, eg:
const decltype(U) &mat() const { return U; }
or:
using mat22 = float[2][2];
const mat22 &mat() const { return U; }
(this latter one as suggested by Daniel H. in comments).
or, in C++14, even just:
const auto &mat() const { return U; }
I have a problem figuring out to use the [] operator to assign a value, i have 2 different errors,
"binary '=': no operator found which takes a right-hand operand of type 'double' (or there is no acceptable conversion)"
no operator "=" matches these operands.
Am I missing something here?
Header
Class CMyVector{
public:
double operator[](const int index) const;
double & operator[](const int index);
CMyVector operator+(const CMyVector mv1);
}
cpp
double CMyVector::operator[](const int index) const
{
return arr[index];
}
double & CMyVector::operator[](const int index)
{
return arr[index];
}
CMyVector CMyVector::operator+(const CMyVector mv1)
{
CMyVector *retval = new CMyVector();
retval[0] = arr[i] + mv1[i];
return *this;
}
CMyVector::operator+ seems weird.
1.retval is a pointer, (i.e. CMyVector *), then retval[i] will be CMyVector, which doesn't make sense for retval[i] = arr[i] + mv1[i];. You might mean (*retval)[i] = arr[i] + mv1[i];. BTW: Here's a memory leak because you didn't delete the pointer.
2.You new a pointer retval, and then set value on it, at last return *this? It doesn't make sense. You might mean:
CMyVector CMyVector::operator+(const CMyVector& mv1)
{
CMyVector retval;
for (int i = 0;i < dim;i++)
{
retval[i] = arr[i] + mv1[i];
}
return retval;
}
CMyVector CMyVector::operator+(const CMyVector mv1)
{
CMyVector *retval = new CMyVector();
for (int i = 0;i < dim;i++)
{
retval[i] = arr[i] + mv1[i];
}
return *this;
}
There are a few issues with this function:
You shouldn't dynamically allocate a CMyVector in order to return by value; that just leaks memory and incurs unnecessary cost. It should just be CMyVector retval;.
Since retval is a pointer, retval[i] is trying to subscript it like an array. You would want (*retval)[i], but since we got rid of the dynamic allocation above, you can just do retval[i].
You return *this instead of *retval. This should now be return retval;.
You should take your argument by-reference to avoid the copy.
operator+ is generally best implemented as a non-member function so that the arguments are treated symmetrically.
The fixed code:
CMyVector operator+(const CMyVector& lhs, const CMyVector& rhs)
{
CMyVector retval;
for (int i = 0; i < dim; i++)
{
retval[i] = lhs[i] + rhs[i];
}
return retval;
}
In the addition operator function, retval is a pointer, which means you must dereference it to use the operator "inline":
(*retval)[i] = ...
Or you could call the operator function explicitly using the "arrow" operator (which does the dereferencing for you):
retval->operator[](i) = ...
However the variable should not be a pointer, since it's the value you should return, which means your operator function is flawed in that it will give you a memory leak and not return the correct value.
See e.g. this operator overloading reference for an example on how to implement it.
I have a class called Coord...it has instance data x, y. I want to override the * operator such that the * operator can be used to multiply the Coord by an integer or double! This is the solution I put up:
Coord& Coord::operator*(int n)
{
this->x = this->x*n;
this->y = this->y*n;
return *this;
}
It works - I've tested some print outs from main...the only issue is...I get a warning from the -Weffc++ flag! It says my function should return by value! I know this flag corresponds to the book "Effective C++" book, but I don't have a copy onhand - what does the book suggest? What is meant to pass by value?
Just to elaborate on Grizzly's comment... This is not the in-place multiplication. As such, you should declare it const to explicitly prevent that:
Coord Coord::operator*(int n) const {
Coord c(*this);
c.x *= n;
c.y *= n;
return c;
}
Or if you have a useful constructor:
Coord Coord::operator*(int n) const {
return Coord(x*n, y*n);
}
The in-place multiplication is different (and non-const):
Coord& Coord::operator*=(int n) {
x *= n;
y *= n;
return *this;
}
You haven't implemented operator* but rather you implemented the self-mutating operator*=, assigning the result back to the original object.
Consider the effects of your operator's implementation for the following int example:
int x = 5;
int y = 2;
int z = x * y;
Now, with integer multiplication implemented similarly to your code, you would end up with both y and z equal to 10.
In order to implement the normal operator* type operators you'll need to create a temporary object and return that by value.
You're probably looking for an implementation more like this (assuming you have a two parameter constructor to your class):
Coord Coord::operator*(int n) const
{
return Coord(x * n, y * n);
}
But note that often, what seems like an obvious meaning of an operator isn't so clear, and overloading simply causes confusion. Consider a non-member named function instead (using a named member scaling function), along these lines:
Coord& Coord::ScaleBy(int n)
{
this->x = this->x*n;
this->y = this->y*n;
return *this;
}
Coord ScaleCoord(Coord c, int n)
{
return c.ScaleBy(n);
}
In general, this sort of thing is done in two parts, a member operator*= and a non-member operator* that uses *=:
Coord& Coord::operator*=(int n) {
x *= n;
y *= n;
return *this;
}
Coord operator*(const Coord& c, int n) {
Coord res(c);
res *= n;
return res;
}
I made my own class template to maintain pair of elements of any type of objects. Now I am going to use this template for another own class MyPoint. this contain 3D cordinates of a point. I think I need to modify this further as my final objective is to use this PairInfor<MyPoint> as a vector<PairInfor<MyPoint> > and again vector<vector<PairInfor<MyPoint> > >. SO, I need your support to modify this as I do not have very knowledge to prepare this types of templates.
I got assistant from some other classes and books, but i need to include most common functions to this. Can anyone help please?
Here is my template class;
// class to accomadate two values
//-------------------------------
#include <stdlib.h>
#include <iostream>
template <class Type>
class PairInfor {
private:
/// two elements of the pair
Type x[2];
public:
// Default constructor.
PairInfor() { x[0] = x[1] = -1; }
// other Constructors.
PairInfor(Type xv, Type yv) {
x[0] = xv; x[1] = yv;
}
PairInfor(const Type *v) { x[0] = v[0]; x[1] = v[1]; }
//constructor for Coping
PairInfor(const PairInfor &v) { x[0] = v.x[0]; x[1] = v.x[1]; }
// Destructor.
~PairInfor() {}
// assignament
PairInfor& operator=(const PairInfor &v)
{ x[0] = v.x[0]; x[1] = v.x[1];
return *this;
}
// Element access, for getting.
Type V1() const { return x[0]; }
// Element access, for getting.
Type V2() const { return x[1]; }
// Element access, for getting.
Type operator[] (int i) const { return x[i]; }
// Element access, for writing.
Type &V1() { return x[0]; }
// Element access, for writing.
Type &V2() { return x[1]; }
// Element access, for writing.
Type &operator[] (int i) { return x[i]; }
// Return a constant reference to the pair
const class PairInfor &infor() const { return *this; }
// Return a reference to the pair
PairInfor &infor() { return *this; }
// comparing two pair packets
friend bool operator == (const PairInfor &v1, const PairInfor &v2)
{
return v1.x[0] == v2.x[0] && v1.x[1] == v2.x[1];
}
};
When I use this template class, I get the following error too.
\include\PairInfor.hpp In constructor `PairInfor<Type>::PairInfor() [with Type = MyPoint]':
\myprogf.cpp instantiated from here
\include\PairInfor.hpp invalid conversion from `int' to `char*'
\include\PairInfor.hpp initializing argument 1 of `MyPoint::MyPoint(char*)'
\Makefile.win [Build Error] [myprogf.o] Error 1
How do I solve this error. Is the error with my default constructor in PairInfor. How do I solve this please?
Thanks in advance.
The following line doesn't work for any type:
PairInfor() { x[0] = x[1] = -1; }
You are trying to assign an integer, but Type may not support that. MyPoint doesn't, hence the error.
You should default-initialize your members:
PairInfor() : x() {}
Note that std::pair might cover your needs already.