Search code examples
c++rvaluetemporary-objects

Is it possible to detect whether object is a temporary from within member function?


I'm implementing a decorator pattern on immutable objects with the pointer-to-implementation idiom. Basically my setup looks like this

struct Object : ObjectBase {
     void doSmth() override {
         impl->doSmth();
     }
     // this is the function I'd like to implement
     Object decorateWith(std::unique_ptr<ObjectDecorator>&&);
private:
     std::unique_ptr<ObjectBase> impl;
};

struct ObjectDecorator : ObjectBase {
    void doSmth() override {
        // do some stuff
        impl->doSmth();
        // do some more stuff
    }
private:
    std::unique_ptr<ObjectBase> impl;
};

Here, the decorateWith function is supposed to have different behavior depending on the whether the object it is callen on is a temporary or not. If it is called on a non-temporary object, it is supposed to return a new Object instance where I have to make a deep copy of the current Object and store it in the unique_ptr of the decorator while the impl pointer of the new Object itself is pointing to the decorator. If, however, decorateWith is called on a temporary, it suffices to create a ObjectDecorator and just move the impl-pointer of the current object into the impl pointer of the decorator and let the object point to the new decorator.

In order to impelement that I need a way to determine from within the call to decorateWith whether the object is a temporary or not and then use tag-dispatch based on the result of that check. Is that possible?

Best Xodion

EDIT: Sample caller code could look like this:

  • decorateWith is called on a non-temporary

    int main() {
        Object x{};
    
        // this call does not modify x so it can be reused later
        Object y = x.decorateWith{std::make_unique<ObjectDecorator>()};
        y.doSmth();
    
        // do some other stuff here
    
        // here, if I had moved the impl-unique_ptr in the decorateWith
        // call this would now segfault since I'd call nullptr->doSmth();
        x.doSmth();
    
    }
    
  • decorateWith is called on a temporary

    int main() {
        Object x = Object{}.decorateWith(std::make_unique<ObjectDecorator>())
                           .decorateWith(std::make_unique<ObjectDecorator>())
                           .decorateWith(std::make_unique<ObjectDecorator>());
         // in this case it would be unneccessary to make a deep copy of all
         // previous instances so I'd like to only move the impl poiner every time
         x.doSmth()
     }
    

Solution

  • You can have ref-qualifiers on member functions. Copied example from en.cppreference.com

    #include <iostream>
    struct S {
        void f() & { std::cout << "lvalue\n"; }
        void f() &&{ std::cout << "rvalue\n"; }
    };
    
    int main(){
        S s;
        s.f();            // prints "lvalue"
        std::move(s).f(); // prints "rvalue"
        S().f();          // prints "rvalue"
    }
    

    So in your situation, you would want to have something like this

     Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
     Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;