繁体   English   中英

带有模板指针的完美转发功能指针

[英]perfect-forwarding with template taking function-pointer

我在本文中找到了一些不错的属性模板。

我希望他们支持完美的转发,但是我不喜欢当前的解决方案:

// 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");

}

没有指定右值设置器的输出(注释掉):

[ ] 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

使用指定的右值设置器输出:

[ ] 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

所以...

它按预期工作,但是我必须分别传递右值设置器的指针,并且每次传递右值时都要检查它是否为null。

有什么建议么?

将类型擦除向下分配给类型T值的操作。 称其为assign_to<T>

让您期望的二传手采取这种类型。

这使该部分(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); }
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM