コンパイラーは、左辺値を右辺値参照にバインドしようとしていると不平を言い続けますが、方法がわかりません。 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
が右辺値として定義されていませんか?なぜそれが左辺値として再解釈されるのですか?
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
ただし、この場合、FastHash<std::string, ... >
をインスタンス化したときにクラスによってすでに決定されているため、関数の呼び出し時にKeyのタイプは推定されません。したがって、実際には右辺値参照の使用を規定しているため、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)
{
// ...
}
値の引数を使用することによる余分なコピーについてあまり心配しないでください。これらはコンパイラによって頻繁に最適化されます。