Lvalue到rvalue引用绑定

Kri*_*ato 17 c++ rvalue-reference move-semantics c++11

编译器一直在抱怨我试图将左值绑定到右值引用,但我看不出如何.我是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.
}
Run Code Online (Sandbox Code Playgroud)

它调用这个方法:

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

我不断收到如下错误:

cannot convert argument 1 from 'std::string' to 'std::string &&'
Run Code Online (Sandbox Code Playgroud)

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

谢谢.

pol*_*ver 26

Insert(key, Value()); // Compiler error here
Run Code Online (Sandbox Code Playgroud)

key这是Key&& key- 这是一个左值!它有一个名字,你可以拿它的地址.只是该左值的类型是"右值引用Key".

你需要传入右值,为此你需要使用std::move:

Insert(std::move(key), Value()); // No compiler error any more
Run Code Online (Sandbox Code Playgroud)

我可以看出为什么这是违反直觉的!但是一旦你区分和右值参考(它是一个与右值相关的参考)和一个实际的右值,它就会变得更加清晰.

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

但是,在这种情况下,调用函数时不会推导出Key的类型,因为在实例化时类已经确定了它FastHash<std::string, ... >.因此,您确实正在使用rvalue引用,因此使用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)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

由于使用了值参数,不要过多担心额外的副本 - 这些通常由编译器优化.

  • @ KristianD'Amato是的; 对于C++ 11,我通常使用[草案n3485](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf),这是公开的免费,并包含一些标准的修复(它本身不是免费的).对于最新的草案,包括C++ 1y功能,您可以使用[cplusplus draft github repository](https://github.com/cplusplus/draft). (3认同)
  • 左值的类型不是"关键"吗?rvalue-reference-ness以什么方式仍然保留? (2认同)
  • @polkadotcadaver我删除了我的答案,因为你的答案要好得多.我的问题是一个语言律师问题.参数`key`的类型为'Key &&`,但除非我对C++的理解错误,否则*expression*`key`是一个类型为`Key`的左值,而不是一个类型为`Key &&`的左值. (2认同)
  • @hvd你是对的;*lvalueness*是表达式的属性,表达式没有引用类型,请参见[expr]/5. (2认同)