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

3

7

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()
     }
    
Hulbard answered 8/6, 2016 at 18:11 Comment(3)
Your explanation might be better backed up with sample calling code.Fuscous
Are you asking to determine whether the Object decorateWith is called from is temporary, or if the argument to decorateWith is temporary?Bacteroid
I want to conditionally move only when the object on which decorateWith is called on is a temporary and make a deep copy otherwise, so it is about how to check whether an object is temporary. As the answers below illustrate there is no need for some kind of type trait since one can overload using ref-qualifiers.Hulbard
S
14

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>&&) &&;
Sepulveda answered 8/6, 2016 at 18:19 Comment(1)
Yes, indeed, but nevertheless the ref-qualifiers are what I need.Hulbard
M
4

You can use reference qualifiers to overload the member function similar to the way you'd use const to overload for const and non-const objects:

Object decorateWith(std::unique_ptr<ObjectDecorator>&&) const&
{
    // implementation if this is not a temporary
}

Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&
{
    // implementation if this IS a temporary
}
Muzzy answered 8/6, 2016 at 18:20 Comment(0)
B
2

Yes. If you implement the following two methods:

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

the second will be called if *this is an rvalue.

Bacteroid answered 8/6, 2016 at 18:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.