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()
}
Explanation: A temporary object is created when an object is returned by value. The temporary object is used to copy the values to another object or to be used in some way. The object holds all the values of the data members of the object.
A temporary object is an unnamed object created by the compiler to store a temporary value.
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>&&) &&;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With