为什么const vector <const pair <... =“” >>给出“无法重载”错误?

时间:2019-01-11 10:55:02

标签: c++ language-lawyer c++17

我有这个简单的代码:

#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。

2 个答案:

答案 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我们要销毁的类型。很公平。我们还需要什么?可擦需要分配器:

  

指定类型的对象可以被给定的分配器破坏。

,这反过来要求Tcv-unqualified

  

T,不符合简历的对象类型

因此您可以拥有std::pair<const string, int>,但不能拥有const std::pair<std::string, int>

从这方面来说,MSVC消息更清晰,因为它直接告诉您是格式错误的分配器。