c++ 左值到右值引用绑定

wztqucjr  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(129)

编译器一直抱怨我试图将左值绑定到右值引用,但我看不出怎么做。我是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 &&'

key在操作符重载中不是被定义为右值吗?为什么它被重新解释为左值?

deyfvvtc

deyfvvtc1#

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

key这里是Key&& 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<std::string, ... >时由类确定了。因此,您实际上是规定了使用右值引用,因此使用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)
{
    // ...
}

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

相关问题