使用模板获取函数指针的完美转发
perfect-forwarding with template taking function-pointer
我在 this article 中找到了一些不错的 属性 模板。
我希望他们支持完美转发,但我不喜欢我目前的解决方案:
// a read-write property which invokes user-defined functions
template <class Type, class Object, const Type&(Object::*real_getter)() const, const Type&(Object::*real_setter)(const Type&), const Type&(Object::*real_mover)(Type&&) = nullptr>
class UnrestrictedProperty {
Object* object;
public:
UnrestrictedProperty(Object* owner_object = nullptr) : object(owner_object) {}
// initializer to specify the owner
void operator()(Object* owner_object) {
this->object = owner_object;
}
// function call syntax
const Type& operator()() const {
return (object->*real_getter)();
}
const Type& operator()(const Type& value) {
return (object->*real_setter)(value);
}
const Type& operator()(Type&& value) {
if (real_mover) return (object->*real_mover)(std::forward<Type>(value));
return (object->*real_setter)(value);
}
// get/set syntax
const Type& get() const {
return (object->*real_getter)();
}
const Type& set(const Type& value) {
return (object->*real_setter)(value);
}
const Type& set(Type&& value) {
if (real_mover) return (object->*real_mover)(std::forward<Type>(value));
return (object->*real_setter)(value);
}
// access with '=' sign
operator const Type&() const {
return (object->*real_getter)();
}
const Type& operator=(const Type& value) {
return (object->*real_setter)(value);
}
const Type& operator=(Type&& value) {
if (real_mover) return (object->*real_mover)(std::forward<Type>(value));
return (object->*real_setter)(value);
}
// comparators
bool operator==(const Type& value) const {
return get() == value;
}
bool operator!=(const Type& value) const {
return not operator==(value);
}
// might be useful for template deductions
typedef Type value_type;
};
// << operator for UnrestrictedProperty
template <class Type, class Object, const Type&(Object::*real_getter)() const, const Type&(Object::*real_setter)(const Type&), const Type&(Object::*real_mover)(Type&&)>
std::ostream& operator<<(std::ostream& output, const UnrestrictedProperty<Type, Object, real_getter, real_setter, real_mover> unrestricted_property) {
return (output << unrestricted_property.get());
}
用法:
// test type that logs constructor, destructor and assignment operator calls
struct TestType {
TestType() { trace("[", this, "] constructor"); }
~TestType() { trace("[", this, "] destructor"); }
TestType(const TestType& other) {
trace("[", this, "] copy constructor copying ", other);
}
TestType& operator=(const TestType& other) {
debug("[", this, "] copy assignment operator");
TestType temporary(other);
trace("[", this, "] swap data with ", temporary);
return *this;
}
TestType& operator=(TestType&& other) {
debug("[", this, "] move assignment operator");
trace("[", this, "] swap data with ", other);
return *this;
}
};
// << operator for TestType
std::ostream& operator<<(std::ostream& output, const TestType& value) {
return (output << "[" << &value << "]");
}
// test object containing an UnrestrictedProperty with custom getter and setter methods
class TestObject {
TestType internal_value;
const TestType& get_value() const {
return internal_value;
}
const TestType& set_value(const TestType& value) {
return (internal_value = value);
}
const TestType& set_value(TestType&& value) {
return (internal_value = std::move(value));
}
public:
// create an UnrestrictedProperty for a TestType value-type in the TestObject class
UnrestrictedProperty<TestType, TestObject, &TestObject::get_value, &TestObject::set_value/*, &TestObject::set_value*/> value;
// (the thrid (commented out) function pointer is the rvalue version of the setter)
TestObject() {
// tell the value property on which object instance it should call the getter and setter methods
value(this);
}
};
void test() {
print("property test starts");
{
print("creating object");
TestObject object;
print("assigning object.value with rvalue");
{
object.value = TestType();
}
print("assigning object.value with lvalue");
{
TestType local = TestType();
object.value = local;
}
print("leaving objects scope");
}
print("property test ends");
}
没有指定右值的输出-setter(注释掉):
[ ] property test starts
[ ] creating object
[T] [0026F22C] constructor
[ ] assigning object.value with rvalue
[T] [0026F157] constructor
[D] [0026F22C] copy assignment operator
[T] [0026EF43] copy constructor copying [0026F157]
[T] [0026F22C] swap data with [0026EF43]
[T] [0026EF43] destructor
[T] [0026F157] destructor
[ ] assigning object.value with lvalue
[T] [0026F223] constructor
[D] [0026F22C] copy assignment operator
[T] [0026EF43] copy constructor copying [0026F223]
[T] [0026F22C] swap data with [0026EF43]
[T] [0026EF43] destructor
[T] [0026F223] destructor
[ ] leaving objects scope
[T] [0026F22C] destructor
[ ] property test ends
具有指定右值的输出-setter:
[ ] property test starts
[ ] create object
[T] [0015F7EC] constructor
[ ] assign object.value with rvalue
[T] [0015F717] constructor
[D] [0015F7EC] move assignment operator
[T] [0015F7EC] swap data with [0015F717]
[T] [0015F717] destructor
[ ] assign object.value with lvalue
[T] [0015F7E3] constructor
[D] [0015F7EC] copy assignment operator
[T] [0015F503] copy constructor copying [0015F7E3]
[T] [0015F7EC] swap data with [0015F503]
[T] [0015F503] destructor
[T] [0015F7E3] destructor
[ ] leaving objects scope
[T] [0015F7EC] destructor
[ ] property test ends
所以...
它按预期工作,但我必须单独传递右值的指针-setter,并且每次传递右值时都必须检查它是否为 null。
有什么建议吗?
类型擦除一直到给T
类型的值赋值的操作。称之为 assign_to<T>
.
有你预期的 setter 那个类型。
这使得该部分 (r vs l) 不再具有多个方法。类型橡皮擦有点费功夫,不过是写一次。
template<class T>
struct assign_to {
std::function<void(T&)> op;
assign_to(T const & t):op([&t](T& dest){dest=t;}){}
assign_to(T&& t):op([&t](T& dest){dest=std::move(t);}){}
assign_to(assign_to&&)=default{}
void write(T& t){ op(t); }
};
我在 this article 中找到了一些不错的 属性 模板。
我希望他们支持完美转发,但我不喜欢我目前的解决方案:
// a read-write property which invokes user-defined functions
template <class Type, class Object, const Type&(Object::*real_getter)() const, const Type&(Object::*real_setter)(const Type&), const Type&(Object::*real_mover)(Type&&) = nullptr>
class UnrestrictedProperty {
Object* object;
public:
UnrestrictedProperty(Object* owner_object = nullptr) : object(owner_object) {}
// initializer to specify the owner
void operator()(Object* owner_object) {
this->object = owner_object;
}
// function call syntax
const Type& operator()() const {
return (object->*real_getter)();
}
const Type& operator()(const Type& value) {
return (object->*real_setter)(value);
}
const Type& operator()(Type&& value) {
if (real_mover) return (object->*real_mover)(std::forward<Type>(value));
return (object->*real_setter)(value);
}
// get/set syntax
const Type& get() const {
return (object->*real_getter)();
}
const Type& set(const Type& value) {
return (object->*real_setter)(value);
}
const Type& set(Type&& value) {
if (real_mover) return (object->*real_mover)(std::forward<Type>(value));
return (object->*real_setter)(value);
}
// access with '=' sign
operator const Type&() const {
return (object->*real_getter)();
}
const Type& operator=(const Type& value) {
return (object->*real_setter)(value);
}
const Type& operator=(Type&& value) {
if (real_mover) return (object->*real_mover)(std::forward<Type>(value));
return (object->*real_setter)(value);
}
// comparators
bool operator==(const Type& value) const {
return get() == value;
}
bool operator!=(const Type& value) const {
return not operator==(value);
}
// might be useful for template deductions
typedef Type value_type;
};
// << operator for UnrestrictedProperty
template <class Type, class Object, const Type&(Object::*real_getter)() const, const Type&(Object::*real_setter)(const Type&), const Type&(Object::*real_mover)(Type&&)>
std::ostream& operator<<(std::ostream& output, const UnrestrictedProperty<Type, Object, real_getter, real_setter, real_mover> unrestricted_property) {
return (output << unrestricted_property.get());
}
用法:
// test type that logs constructor, destructor and assignment operator calls
struct TestType {
TestType() { trace("[", this, "] constructor"); }
~TestType() { trace("[", this, "] destructor"); }
TestType(const TestType& other) {
trace("[", this, "] copy constructor copying ", other);
}
TestType& operator=(const TestType& other) {
debug("[", this, "] copy assignment operator");
TestType temporary(other);
trace("[", this, "] swap data with ", temporary);
return *this;
}
TestType& operator=(TestType&& other) {
debug("[", this, "] move assignment operator");
trace("[", this, "] swap data with ", other);
return *this;
}
};
// << operator for TestType
std::ostream& operator<<(std::ostream& output, const TestType& value) {
return (output << "[" << &value << "]");
}
// test object containing an UnrestrictedProperty with custom getter and setter methods
class TestObject {
TestType internal_value;
const TestType& get_value() const {
return internal_value;
}
const TestType& set_value(const TestType& value) {
return (internal_value = value);
}
const TestType& set_value(TestType&& value) {
return (internal_value = std::move(value));
}
public:
// create an UnrestrictedProperty for a TestType value-type in the TestObject class
UnrestrictedProperty<TestType, TestObject, &TestObject::get_value, &TestObject::set_value/*, &TestObject::set_value*/> value;
// (the thrid (commented out) function pointer is the rvalue version of the setter)
TestObject() {
// tell the value property on which object instance it should call the getter and setter methods
value(this);
}
};
void test() {
print("property test starts");
{
print("creating object");
TestObject object;
print("assigning object.value with rvalue");
{
object.value = TestType();
}
print("assigning object.value with lvalue");
{
TestType local = TestType();
object.value = local;
}
print("leaving objects scope");
}
print("property test ends");
}
没有指定右值的输出-setter(注释掉):
[ ] property test starts [ ] creating object [T] [0026F22C] constructor [ ] assigning object.value with rvalue [T] [0026F157] constructor [D] [0026F22C] copy assignment operator [T] [0026EF43] copy constructor copying [0026F157] [T] [0026F22C] swap data with [0026EF43] [T] [0026EF43] destructor [T] [0026F157] destructor [ ] assigning object.value with lvalue [T] [0026F223] constructor [D] [0026F22C] copy assignment operator [T] [0026EF43] copy constructor copying [0026F223] [T] [0026F22C] swap data with [0026EF43] [T] [0026EF43] destructor [T] [0026F223] destructor [ ] leaving objects scope [T] [0026F22C] destructor [ ] property test ends
具有指定右值的输出-setter:
[ ] property test starts [ ] create object [T] [0015F7EC] constructor [ ] assign object.value with rvalue [T] [0015F717] constructor [D] [0015F7EC] move assignment operator [T] [0015F7EC] swap data with [0015F717] [T] [0015F717] destructor [ ] assign object.value with lvalue [T] [0015F7E3] constructor [D] [0015F7EC] copy assignment operator [T] [0015F503] copy constructor copying [0015F7E3] [T] [0015F7EC] swap data with [0015F503] [T] [0015F503] destructor [T] [0015F7E3] destructor [ ] leaving objects scope [T] [0015F7EC] destructor [ ] property test ends
所以...
它按预期工作,但我必须单独传递右值的指针-setter,并且每次传递右值时都必须检查它是否为 null。
有什么建议吗?
类型擦除一直到给T
类型的值赋值的操作。称之为 assign_to<T>
.
有你预期的 setter 那个类型。
这使得该部分 (r vs l) 不再具有多个方法。类型橡皮擦有点费功夫,不过是写一次。
template<class T>
struct assign_to {
std::function<void(T&)> op;
assign_to(T const & t):op([&t](T& dest){dest=t;}){}
assign_to(T&& t):op([&t](T& dest){dest=std::move(t);}){}
assign_to(assign_to&&)=default{}
void write(T& t){ op(t); }
};