2015-06-25 8 views
10

Qualcuno può spiegare a me perché questo non riescono a compilare:C++ 11 errori di compilazione con std :: movimento e std :: make_move_iterator

#include <iterator> 
#include <iostream> 
#include <unordered_set> 
#include <utility> 
#include <set> 

template<typename T> 
std::unordered_set<T> FailMove(std::set<T> &&set) { 
    std::unordered_set<T> response; 
    response.insert(std::make_move_iterator(set.begin()), 
        std::make_move_iterator(set.end())); 
    return response; 
} 

int main(int argc, char **argv) { 
    std::set<int> set{1, 3, 5, 7}; 

    auto res = FailMove(std::move(set)); 
    std::cout << res.size() << '\n'; 

    return 0; 
} 

L'output clang (comando: clang++ -std=c++11 -otest test.cpp) è:

In file included from test.cpp:1: 
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iterator:948:14: error: cannot 
     cast from lvalue of type 'const value_type' (aka 'const int') to rvalue reference type 'reference' (aka 'int &&'); types are not 
     compatible 
     return static_cast<reference>(*__i); 
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/unordered_set:830:34: note: in 
     instantiation of member function 'std::__1::move_iterator<std::__1::__tree_const_iterator<int, std::__1::__tree_node<int, void *> *, 
     long> >::operator*' requested here 
     __table_.__insert_unique(*__first); 
           ^
test.cpp:10:12: note: in instantiation of function template specialization 'std::__1::unordered_set<int, std::__1::hash<int>, 
     std::__1::equal_to<int>, std::__1::allocator<int> >::insert<std::__1::move_iterator<std::__1::__tree_const_iterator<int, 
     std::__1::__tree_node<int, void *> *, long> > >' requested here 
    response.insert(std::make_move_iterator(set.begin()), 
     ^
test.cpp:18:14: note: in instantiation of function template specialization 'FailMove<int>' requested here 
    auto res = FailMove(std::move(set)); 
      ^
1 error generated. 

uscita gcc (comando: g++ -std=c++11 -otest test.cpp):

In file included from /usr/include/c++/4.8/iterator:63:0, 
       from test.cpp:1: 
/usr/include/c++/4.8/bits/stl_iterator.h: In instantiation of 'std::move_iterator<_Iterator>::value_type&& std::move_iterator<_Iterator>::operator*() const [with _Iterator = std::_Rb_tree_const_iterator<int>; std::move_iterator<_Iterator>::reference = int&&; std::move_iterator<_Iterator>::value_type = int]': 
/usr/include/c++/4.8/bits/hashtable_policy.h:647:18: required from 'void std::__detail::_Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::insert(_InputIterator, _InputIterator) [with _InputIterator = std::move_iterator<std::_Rb_tree_const_iterator<int> >; _Key = int; _Value = int; _Alloc = std::allocator<int>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<int>; _H1 = std::hash<int>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, true, true>]' 
/usr/include/c++/4.8/bits/unordered_set.h:393:4: required from 'void std::unordered_set<_Value, _Hash, _Pred, _Alloc>::insert(_InputIterator, _InputIterator) [with _InputIterator = std::move_iterator<std::_Rb_tree_const_iterator<int> >; _Value = int; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<int>]' 
test.cpp:10:3: required from 'std::unordered_set<T> FailMove(std::set<T>&&) [with T = int]' 
test.cpp:18:37: required from here 
/usr/include/c++/4.8/bits/stl_iterator.h:963:37: error: invalid initialization of reference of type 'std::move_iterator<std::_Rb_tree_const_iterator<int> >::reference {aka int&&}' from expression of type 'std::remove_reference<const int&>::type {aka const int}' 
     { return std::move(*_M_current); } 

Tuttavia questo codice fa compi le in entrambi i compilatori senza problemi: la versione

#include <iterator> 
#include <iostream> 
#include <unordered_map> 
#include <utility> 
#include <map> 

template<typename K, typename V> 
std::unordered_map<K, V> FailMove(std::map<K, V> &&map) { 
    std::unordered_map<K, V> response; 
    response.insert(std::make_move_iterator(map.begin()), 
        std::make_move_iterator(map.end())); 
    return response; 
} 

int main(int argc, char **argv) { 
    std::map<int, int> map{{1, 1}, {3, 3}, {5, 5}, {7, 7}}; 

    auto res = FailMove(std::move(map)); 
    std::cout << res.size() << '\n'; 

    return 0; 
} 

clang testato: versione

Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) 
Target: x86_64-apple-darwin14.3.0 
Thread model: posix 

gcc testato:

g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2 
Copyright (C) 2013 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+2

È stato compilato con successo per me http://coliru.stacked-crooked.com/a/f3bf16d2a8290b17 – Steephen

+0

Non riesco a visualizzare Visual Studio 2013, in modo abbastanza strano. errore C2440: 'return': non può convertire da 'const int' a 'int &&' "essendo uno dei gran numero di errori che ottengo Edit: e il tuo secondo esempio si compila bene, come previsto – Robinson

+0

@Robinson se leggi l'errore messaggi, questo è esattamente l'errore in clang. Non sono abbastanza sicuro di gcc. – Sambatyon

risposta

7

La versione corta è set::begin() restituisce un const_iterator mentre map::begin() restituisce un iterator. Non è possibile passare da un const_iterator.

La versione lunga è che il componente "Chiave" di contenitori associativi viene considerato come const all'interno del contenitore. A set non contiene nient'altro che un componente chiave. A map contiene sia un componente chiave sia un componente Valore. I valori di set sono chiavi. I valori di map sono std::pair< const Key, Value >.

Questo perché la modifica del componente Chiave di un contenitore standard in un modo che modifica l'ordine degli elementi interrompe gli invarianti del contenitore. Questo è vero anche se intendi scartarlo brevemente, in quanto anche il traversal, la distruzione o qualsiasi altra cosa può essere interrotta (in teoria) modificando i componenti chiave!


Quando si sposta da un iteratore it, tenta di lanciare *it-value_type&&. Per un iteratore const, *it restituisce value_type const& e il cast non riesce.

In caso di map, lo spostamento sposterà il componente Valore e copierà il componente Chiave.

+2

Sembra che "move_iterator :: reference" sia stato modificato in [LWG 2106] (http://wg21.link/lwg2106) da basato su 'value_type' per essere basato su' reference', il codice nell'OP si compila con GCC 5.1. –

+1

@ T.C.Ah: compila, ma "non riesce a funzionare" in quanto l'iteratore di movimento presunto non si muove (a meno che il tipo di valore non abbia uno stato mutabile e un costruttore di spostamenti 'const &&' che sia). Sembra "la cosa giusta da fare". – Yakk

Problemi correlati