std::move 和 std::make_move_iterator 的 C++11 编译错误
C++11 compilation errors with std::move and 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;
}
clang 输出(命令: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.
gcc 输出(命令: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); }
但是这段代码在两个编译器中编译都没有问题:
#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 版本:
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 版本:
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.
短版是 set::begin()
returns 一个 const_iterator
而 map::begin()
returns 一个 iterator
。您不能从 const_iterator
.
移动
长版本是关联容器的 "Key" 组件在容器内被视为 const
。 set
只包含一个 Key 组件。 map
包含 Key 组件和 Value 组件。 set
的值是键。 map
的值为 std::pair< const Key, Value >
.
这是因为以更改元素顺序的方式修改标准容器的 Key 组件会破坏容器的不变量。即使您打算很快丢弃它也是如此,因为即使遍历、破坏或其他任何东西都可以通过编辑关键组件来破坏(理论上)!
当您从迭代器 it
移动时,它会尝试将 *it
转换为 value_type&&
。对于 const 迭代器,*it
returns value_type const&
,转换失败。
在map
的情况下,移动会移动Value组件,并复制Key组件。
谁能给我解释一下为什么编译失败:
#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;
}
clang 输出(命令: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.
gcc 输出(命令: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); }
但是这段代码在两个编译器中编译都没有问题:
#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 版本:
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 版本:
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.
短版是 set::begin()
returns 一个 const_iterator
而 map::begin()
returns 一个 iterator
。您不能从 const_iterator
.
长版本是关联容器的 "Key" 组件在容器内被视为 const
。 set
只包含一个 Key 组件。 map
包含 Key 组件和 Value 组件。 set
的值是键。 map
的值为 std::pair< const Key, Value >
.
这是因为以更改元素顺序的方式修改标准容器的 Key 组件会破坏容器的不变量。即使您打算很快丢弃它也是如此,因为即使遍历、破坏或其他任何东西都可以通过编辑关键组件来破坏(理论上)!
当您从迭代器 it
移动时,它会尝试将 *it
转换为 value_type&&
。对于 const 迭代器,*it
returns value_type const&
,转换失败。
在map
的情况下,移动会移动Value组件,并复制Key组件。