代码之家  ›  专栏  ›  技术社区  ›  Raildex

我可以禁止临时对象作为参数吗?

  •  2
  • Raildex  · 技术社区  · 4 年前

    假设我有一个函数:

    void foo(Object& o) {
        /* only query o, dont alter it*/
    }
    

    是否可以仅使用已构造的对象调用此函数,并且如果我使用临时对象调用该函数,则Visual Studio会引发编译错误?

    struct Object {
        /*Members*/
    }
    
    void foo(Object& o) {
        /* only query o, dont alter it*/
    }
    
    int main() {
        Object o = Object();
        foo(o); // allow this
        foo(Object()) // but disallow this
    }
    
    1 回复  |  直到 4 年前
        1
  •  10
  •   asmmo    4 年前

    如果参数不是 const ,函数不接受临时变量。

    常量 ,函数同时接受临时对象和常规对象。

    但是如果你想阻止这种情况,你可以使用以下方法

    struct Object{};
    void foo(const Object& o) {
        /*only query o, don't alter it*/
    }
    void foo(Object&& ) = delete;
    
    int main() {
        Object o;
        foo(o); // allow this
        foo(Object{}); // but disallow this
    }
    

    Live

        2
  •  4
  •   dfrib    4 年前

    显式删除 const &&

    临时对象可以通过将其绑定到 const 但在函数中不能绑定它- 常量 不能用临时对象调用 常量 (即使实现只查询而不改变对象)。这可以说是违反了 常量 正确性。

    当你的自由函数API正在检查 Object 对象时,可以考虑将其更改为成员函数,并使用ref限定符显式删除将由临时对象的重载解析选择的重载。第一种方法是简单地删除 && 超载:

    struct Object {
        // ...
        
        void foo() const & {}
        void foo()       && = delete;
    };
    
    int main() {
        Object o = Object();
        const Object co = Object();
    
        o.foo();
        co.foo();
        
        //Object().foo();  // error: use of deleted function
    }
    

    然而,这并没有禁止,尽管有点做作 以及 从常量对象移动 常量 Rvalueref限定符重载对于 右值参数:

    std::move(co).foo();  // Accepted.
    static_cast<const Object&&>(Object()).foo();  // Accepted.
    

    因此,不是显式删除 && 重载,我们也可以通过显式删除 超载,因为这也将是超载非的选择- 常量 临时对象:

    struct Object {
        // ...
        
        void foo() const & {}
        void foo() const && = delete;
    };
    
    int main() {
        Object o = Object();
        const Object co = Object();
    
        o.foo();
        co.foo();
        
        //std::move(o).foo();   // error: use of deleted function
        //std::move(co).foo();  // error: use of deleted function
    
        //Object().foo();  // error: use of deleted function
        //static_cast<const volatile Object&&>(Object()).foo();  // error: use of deleted function
    }
    

    我们可能会注意到,使用相同的方法,例如 std::ref std::cref 的帮助函数 std::reference_wrapper [functional.sym] :

    // [refwrap], reference_­wrapper
    // ...
    template <class T> void ref(const T&&) = delete;
    template <class T> void cref(const T&&) = delete;
    
    // ...
    

    因为您很自然地想要删除临时对象的引用包装器。