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()
}
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>&&) &&;