Home > Net >  User defined conversion assigned to const ref variable via temporary object
User defined conversion assigned to const ref variable via temporary object

Time:09-17

The code below is a simplified version of the actual problem I am facing.

Assume I do not have permission to modify class A (as it is external library), and its already widely used in my existing code base.

The const & assignment from a temporary object (direct constructor) which also return a const & member variable via implicit conversion is not valid in this case.

How do I prevent or make it legal in this case so that the caller gets the correct A value?

class A 
{
public:
    A() {  }
    A(int _r, int _g, int _b)
        : r(_r), g(_g), b(_b)
    {
    }

    ~A(){ }

    int GetR() const {  return r; }
    int GetG() const { return g; }
    int GetB() const { return b; }

private:
    int r = 0;
    int g = 0;
    int b = 0;
};

class Foo
{
public:
    Foo() : Foo(A()) {}
    Foo(int _r, int _g, int _b) : a(A(_r, _g, _b)) {}
    explicit Foo(const A& _a) : a(_a) {}

    Foo& operator=(const A& a)
    {
        *this = Foo(a);
        return *this;
    }

    operator A() const { return a; }
    operator const A&() const {  return a; }

private:
    A a;
};

int main()
{
    const A& a = Foo(200, 100, 300); 
    std::cout << a.GetR() << a.GetG() << a.GetB() << endl; // I may not get 200 100 300 here as Foo is already out of scope 

    return 0;
}

Motivation

Some background on why I am implementing a class as above. The actual purpose of class Foo is to contain 2 different objects, which actually has the same purpose, just different way of storing data internally. For example, let's say class A and class B, which stores RGB value of color in int and floating (normalized) respectively. And as mentioned above, I do not have permission to modify class A, and its already widely used in my code base.

There are tons of function in my code base which takes in const A& and const B& as a function param. So I am trying to unify this 2 classes for a particular case, where I can just pass in Foo in those places and it will work as expected.

CodePudding user response:

You can apply ref-qualified member functions (since C 11), i.e. mark the conversion operator with lvalue-reference, to prevent it being called on temporaries (rvalues).

class Foo
{
public:
    ... ...

    operator A() const { return a; }
    operator const A&() const & {  return a; }
    operator const A&() && = delete;

    ... ...
};

Then

const A& a = Foo(200, 100, 300);                 // invalid; invokes deleted operator
const A& a = static_cast<A>(Foo(200, 100, 300)); // fine; invokes operator A()
  • Related