是否可以从成员函数中检测对象是否是临时对象?
Is it possible to detect whether object is a temporary from within member function?
我正在使用指向实现的指针在不可变对象上实现装饰器模式。基本上我的设置是这样的
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;
};
在这里,decorateWith 函数应该有不同的行为,这取决于调用它的对象是否是临时对象。如果在非临时对象上调用它,它应该 return 一个新的对象实例,我必须在其中制作当前对象的深层副本并将其存储在装饰器的 unique_ptr 中,同时新对象本身的 impl 指针指向装饰器。
但是,如果临时调用 decorateWith,则创建一个 ObjectDecorator 并将当前对象的 impl 指针移动到装饰器的 impl 指针并让对象指向新装饰器就足够了。
为了实现这一点,我需要一种方法来从对 decorateWith 的调用中确定该对象是否是临时对象,然后根据该检查的结果使用标记分派。这可能吗?
最佳
Xodion
编辑:示例调用者代码可能如下所示:
decorateWith 在非临时对象上调用
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 被临时调用
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()
}
您可以在成员函数上使用引用限定符。从 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"
}
所以在你的情况下,你会想要这样的东西
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;
您可以使用引用限定符重载成员函数,类似于您使用 const
重载 const
和非 const
对象的方式:
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
}
是的。如果实现以下两种方法:
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;
如果 *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;
};
在这里,decorateWith 函数应该有不同的行为,这取决于调用它的对象是否是临时对象。如果在非临时对象上调用它,它应该 return 一个新的对象实例,我必须在其中制作当前对象的深层副本并将其存储在装饰器的 unique_ptr 中,同时新对象本身的 impl 指针指向装饰器。 但是,如果临时调用 decorateWith,则创建一个 ObjectDecorator 并将当前对象的 impl 指针移动到装饰器的 impl 指针并让对象指向新装饰器就足够了。
为了实现这一点,我需要一种方法来从对 decorateWith 的调用中确定该对象是否是临时对象,然后根据该检查的结果使用标记分派。这可能吗?
最佳 Xodion
编辑:示例调用者代码可能如下所示:
decorateWith 在非临时对象上调用
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 被临时调用
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() }
您可以在成员函数上使用引用限定符。从 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"
}
所以在你的情况下,你会想要这样的东西
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;
您可以使用引用限定符重载成员函数,类似于您使用 const
重载 const
和非 const
对象的方式:
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
}
是的。如果实现以下两种方法:
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &;
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&;
如果 *this
是右值,将调用第二个。