【问题标题】:Lvalue to rvalue reference binding左值到右值引用绑定
【发布时间】:2014-01-02 05:26:56
【问题描述】:

编译器一直抱怨我试图将左值绑定到右值引用,但我看不出如何。我是 C++11 的新手,移动语义等,所以请多多包涵。

我有这个功能:

template <typename Key, typename Value, typename HashFunction, typename Equals>
Value& FastHash<Key, Value, HashFunction, Equals>::operator[](Key&& key)
{
    //  Some code here...

    Insert(key, Value()); // Compiler error here

    //   More code here.
}

调用此方法:

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(Key&& key, Value&& value)
{
    // ...
}

我不断收到如下错误:

cannot convert argument 1 from 'std::string' to 'std::string &&'

在 Insert() 调用上。 key 不是在运算符重载中定义为右值吗?为什么它被重新解释为左值?

【问题讨论】:

    标签: c++ c++11 move-semantics rvalue-reference


    【解决方案1】:
    Insert(key, Value()); // Compiler error here
    

    key 这里是Key&amp;&amp; key - 这是一个左值!它有一个名字,你可以取它的地址。只是该左值的类型是“对Key的右值引用”。

    您需要传入一个右值,为此您需要使用std::move

    Insert(std::move(key), Value()); // No compiler error any more
    

    我明白为什么这是违反直觉的!但是,一旦你区分了右值引用(即绑定到右值的引用)和实际的右值,它就会变得更加清晰。

    编辑:这里真正的问题是使用右值引用。在推导参数类型的函数模板中使用它们是有意义的,因为由于引用折叠规则,这允许参数绑定到左值引用或右值引用。请参阅这篇文章和视频了解原因:http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

    但是,在这种情况下,在调用函数时不会推断出 Key 的类型,因为它在您实例化 FastHash&lt;std::string, ... &gt; 时已经由类确定。因此,您确实是在规定使用右值引用,因此使用 std::move 可以修复代码。

    我会将您的代码更改为参数按值获取:

    template <typename Key, typename Value, typename HashFunction, typename Equals>
    Value& FastHash<Key, Value, HashFunction, Equals>::operator[](Key key)
    {
        //  Some code here...
    
        Insert(std::move(key), Value());
    
        //   More code here.
    }
    
    template <typename Key, typename Value, typename HashFunction, typename Equals>
    void FastHash<Key, Value, HashFunction, Equals>::Insert(Key key, Value value)
    {
        // ...
    }
    

    不要太担心由于使用值参数而导致的额外副本 - 这些经常被编译器优化。

    【讨论】:

    • 左值的类型不就是“Key”吗?以何种方式仍然保留右值引用?
    • 这可行,但我不确定我是否理解 hvd 提出的问题。你能解释一下吗?
    • @polkadotcadaver 我删除了我的答案,因为你的答案要好得多。我的问题是语言律师问题。参数key 的类型为Key&amp;&amp;,但除非我对C++ 的理解在这里是错误的,否则表达式 keyKey 类型的左值,而不是Key&amp;&amp; 类型的左值.
    • @hvd 你说得对; lvalueness 是表达式的属性,表达式没有引用类型,参见 [expr]/5。
    • @KristianD'Amato 是的;对于 C++11,我通常使用 draft n3485,它是免费公开的,并且包含对标准的一些修复(它本身不是免费的)。对于最新的草稿,包括 C++1y 功能,您可以使用cplusplus draft github repository
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 2014-10-31
    • 2017-04-13
    • 2011-02-14
    • 2018-09-30
    • 1970-01-01
    相关资源
    最近更新 更多