0

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.

jepugs
  • 445
  • 4
  • 10

3 Answers3

6

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]; }
//                               ^^^^
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Ran into this answer by accident, and it made me curious, are there reasons why you would want to assign values to temporary members this way? – SPMP Aug 26 '16 at 14:44
  • @user2308211: It'd be very unusual. The comment is actually wrong (fixing now); the code is valid in C++03, too. An ordinary, unqualified member function can be invoked on a temporary. The ref-qualifier would be useful if you wanted to allow a member function call *only* on an rvalue. Possible use cases for that would be "consuming" kinds of operations: `{ T & foo() & { return x_; } T && foo() && { return std::move(x_); }` That is, you may want to allow someone to steal the internals, but only if they have an rvalue. – Kerrek SB Aug 26 '16 at 15:02
  • @user2308211: Even then it'd be kind of unusual, since the user could always just write `std::move(y.foo())`, instead of `std::move(y).foo()`. – Kerrek SB Aug 26 '16 at 15:03
  • @user2308211: I think what I might have meant to say (back when I didn't know any C++!) was that `vec4().x` is not assignable, because it's an rvalue in 03, a prvalue in 11 and an xvalue in 14, but using a member function always allows you to convert rvalues to lvalues (because `*this` is always an lvalue). – Kerrek SB Aug 26 '16 at 15:05
  • Perhaps this will allow complicated functions to be evaluated for literals? What I mean is, if we have class that has a tricky member function that stores results into a member variable, and then we wish to call the function with some literals? Would that be a possible use case? – SPMP Aug 26 '16 at 15:19
  • 1
    @user2308211: Yes, you could do that, but the question is why you would need to *constrain* the function the be called only on rvalues. You could always just leave the qualification off entirely if it's all the same to you. – Kerrek SB Aug 26 '16 at 15:37
4

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];.

Anteru
  • 19,042
  • 12
  • 77
  • 121
4

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.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Yeah, I just looked up r-value references again, and I guess I misunderstood what an r-value was in the first place. I'll change the question's title now. Thanks! – jepugs Dec 31 '12 at 16:42