2013-12-14 19 views
11

Kompilator utrzymuje skarży Próbuję powiązać lwartością do odniesienia rvalue, ale nie widzę w jaki sposób. Jestem nowy w C++ 11, poruszam semantykę itp., Więc proszę o zachowanie mnie.lwartości do rvalue wiążące odniesienie

mam tej funkcji:

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. 
} 

który wywołuje tę metodę:

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

trzymam błędy uzyskiwanie tak:

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

na Insert() rozmowy. Czy nie jest key zdefiniowana jako wartość runt w przeciążeniu operatora? Dlaczego jest on ponownie interpretowany jako l-wartość?

Dzięki.

Odpowiedz

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

key tutaj jest Key&& key - to jest lwartość! Ma nazwę i możesz wziąć jego adres. Chodzi o to, że typ tej lwartości to "rvalue reference to Key".

Trzeba zdać w rvalue, a do tego trzeba użyć std::move:

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

mogę zrozumieć, dlaczego jest to sprzeczne z intuicją! Ale po rozróżnieniu między wartością odniesienia rwartości (która jest odniesieniem do wartości r) a rzeczywistą wartością rublowy staje się jaśniejszy.

Edit: prawdziwym problemem tutaj jest za pomocą odniesień rvalue w ogóle. Sensowne jest użycie ich w szablonie funkcji, w którym wywodzi się typ argumentu, ponieważ pozwala to na powiązanie argumentu z odwołaniem do lwartości lub odwołaniem do rwartości, ze względu na reguły zwijania odniesienia. Zobacz ten artykuł i wideo, dlaczego: http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

Jednak w tym przypadku typ klucza nie jest wyprowadzany podczas wywoływania funkcji, ponieważ został już określony przez klasę podczas tworzenia instancji FastHash<std::string, ... >. Tak naprawdę przepisujesz używanie odwołań rvalue, a zatem użycie std::move naprawia kod.

chciałbym zmienić swój kod, że parametry są brać pod względem wartości:

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) 
{ 
    // ... 
} 

nie martw się zbytnio o dodatkowych kopii na skutek korzystania z argumentów wartości - są często optymalizowane przez kompilator.

+2

nie Czy typ lwartości właśnie „klucz”? W jaki sposób zachowuje się nadal odniesienie do rwartości? – hvd

+0

To działa, ale nie jestem pewien, rozumiem problem, który podniósł hvd. Czy możesz wytłumaczyć? –

+0

@hvd Zostało to zachowane, ponieważ nie ma tam odliczania typu argumentacyjnego - zobacz moją edycję. – polkadotcadaver

Powiązane problemy