dimanche 27 mars 2016

Non-friend single-line operator + overload based on operator +=

Let's say I have a class:

class A
{
    //...
};

With well defined operator +=:

A& operator +=(const A&) {return *this;} //class without members

So let's try to overload operator+ also (as non-friend). I don't want to use class name to call constructor of temporary object (kinda want this make generic code):

A operator +(const A& other) const
{
    return auto(*this)(*this) += other; //error: invalid use of auto
//         /\/\/\/\/\    /\      
//        type of *this  ||
//                 constructor call
}

auto is no good here. Let's try decltype.

A operator +(const A& other) const
{
    return decltype(*this)(*this) += other; //error: 'A& A::operator+=(const A&)' discards
//         /\/\/\/\/\/\/\    /\                      qualifiers [-fpermissive] return
//          type of *this    ||                      decltype(*this)(*this) += other;
//                    constructor call                                      ^
}

This managed to get the type out of *this, but operator+ is declared const, so we got const A deduced (that's what I thought). So let's go on:

A operator +(const A& other) const
{
    return typename std::remove_const<decltype(*this)>::type(*this) += amount; 
    //same error as previous
}

Now I got mindblown. Even thought I removed constness, it still discards qualifier. Well, maybe that's because all I was doing was just CASTING. So stupid. To call a constructor I would have to generate code that (besides type) has ::Constructor (so I even tried to make an alias for constructor, but at this point I failed so hard). My broken brain gave up, but rest of my consciousness gave me an solution (which is generic in writing, so that's good):

// outside of class
template<class A>
inline A&& make_rvalue(A copy)
{
    return std::move(copy);
}

// inside of class
A operator +(const A& other) const
{
    return make_rvalue(*this) += other; // such generic code
}

That's what I ended with. But is there some trick that doesn't involve any other function call?

Aucun commentaire:

Enregistrer un commentaire