我有这个简单的代码:
#include <vector>
#include <string>
void foo(const std::vector<std::pair<std::string, int> > & networks) {
for (auto p : networks) {
}
}
void bla(const std::vector<const std::pair<std::string, int> > & networks) {
for (auto p : networks) {
}
}
这会在bla()
中产生错误:
mrvn@frosties:~% g++ -O2 -W -Wall -g -std=gnu++17 -c bla.cc
In file included from /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:33:0,
from /usr/include/c++/5/bits/allocator.h:46,
from /usr/include/c++/5/vector:61,
from bla.cc:1:
/usr/include/c++/5/ext/new_allocator.h: In instantiation of ‘struct __gnu_cxx::new_allocator<const std::pair<std::__cxx11::basic_string<char>, int> >’:
/usr/include/c++/5/bits/allocator.h:92:11: required from ‘class std::allocator<const std::pair<std::__cxx11::basic_string<char>, int> >’
/usr/include/c++/5/bits/stl_vector.h:79:14: required from ‘struct std::_Vector_base<const std::pair<std::__cxx11::basic_string<char>, int>, std::allocator<const std::pair<std::__cxx11::basic_string<char>, int> > >::_Vector_impl’
/usr/include/c++/5/bits/stl_vector.h:164:20: required from ‘struct std::_Vector_base<const std::pair<std::__cxx11::basic_string<char>, int>, std::allocator<const std::pair<std::__cxx11::basic_string<char>, int> > >’
/usr/include/c++/5/bits/stl_vector.h:214:11: required from ‘class std::vector<const std::pair<std::__cxx11::basic_string<char>, int> >’
bla.cc:10:17: required from here
/usr/include/c++/5/ext/new_allocator.h:93:7: error: ‘const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = const std::pair<std::__cxx11::basic_string<char>, int>; __gnu_cxx::new_allocator<_Tp>::const_pointer = const std::pair<std::__cxx11::basic_string<char>, int>*; __gnu_cxx::new_allocator<_Tp>::const_reference = const std::pair<std::__cxx11::basic_string<char>, int>&]’ cannot be overloaded
address(const_reference __x) const _GLIBCXX_NOEXCEPT
^
/usr/include/c++/5/ext/new_allocator.h:89:7: error: with ‘_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = const std::pair<std::__cxx11::basic_string<char>, int>; __gnu_cxx::new_allocator<_Tp>::pointer = const std::pair<std::__cxx11::basic_string<char>, int>*; __gnu_cxx::new_allocator<_Tp>::reference = const std::pair<std::__cxx11::basic_string<char>, int>&]’
address(reference __x) const _GLIBCXX_NOEXCEPT
^
我的问题是:为什么?
注意:使用的是g ++ 5.4和7.3。
答案 0 :(得分:5)
到目前为止,我可以从标准和文档中收集到以下信息:
std::vector
是一个allocator-aware容器。
根据C ++ 17(最终工作草案N4659)
20.5.3.5分配器要求
[allocator.requirements]
表30说:
T,U,C任何 cv不合格对象类型(6.9)
对于std::vector
,还要求元素类型是完整类型并满足Erasable的要求。
在[container.requirements.general]/15
中,我们有:
给出分配器类型A并给定具有X的容器类型X 与T相同的value_type和与T相同的allocator_-类型
allocator_traits<A>::rebind_alloc<T>
并给定类型m
的左值A
, 类型为p
的指针T*
,类型为v
(可能是const)的表达式T
, 以及类型为rv
的右值T
,定义了以下术语。
...
(15.6)— T可从X擦除,表示以下表达式是 格式正确的:allocator_traits<A>::destroy(m, p)
由于问题中的元素类型为const
限定,因此不符合要求。
答案 1 :(得分:3)
在向量中必须具有非const值:
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0 /../../../../ include / c ++ / 8.2.0 / bits / stl_vector.h:351:7:错误:由于要求'is_same,分配器>,int>> :: type,const对,分配器>,int>> :: value',导致static_assert失败,“ std :: vector必须具有非常量,非易失性value_type”
让我们从向量需求开始,直到分配器问题。 vector
中的类型必须支持:
对元素施加的要求取决于对容器执行的实际操作。通常,要求元素类型满足Erasable的要求,但是许多成员函数提出了更严格的要求。如果分配器满足分配器完整性要求,则可以使用一个不完整的元素类型实例化此容器(但不能使用其成员)。
因此,我们需要拥有可以Erasable
并且可以做的事情:
std::allocator_traits<A>::destroy(m, p);
使用m
分配器和p
我们要销毁的类型。很公平。我们还需要什么?可擦需要分配器:
指定类型的对象可以被给定的分配器破坏。
,这反过来要求T
为cv-unqualified:
T,不符合简历的对象类型
因此您可以拥有std::pair<const string, int>
,但不能拥有const std::pair<std::string, int>
。
从这方面来说,MSVC消息更清晰,因为它直接告诉您是格式错误的分配器。