【问题标题】:C++11-related compilation error with g++ 4.6 and boost::unordered_mapg++ 4.6 和 boost::unordered_map 的 C++11 相关编译错误
【发布时间】:2012-11-20 15:53:13
【问题描述】:

我有一些 C++ 代码失败并出现编译错误,除非它在 ​​C++11 模式下运行,但我无法弄清楚为什么会出现这种情况,因为代码没有(明确)使用 C ++11 个特点:

#include <vector>
#include <map>
#include <boost/unordered_map.hpp>

struct SomeStruct {
  boost::unordered_map<int, int> intMap;
};

int main(int argc, const char* argv[]) {
  std::vector<SomeStruct> vals;

  vals.resize(100);
}

在使用 gcc 4.6.3-1ubuntu5 和 boost 1.48 的 Ubuntu 12.04 64 位机器上编译时:

g++ test.cpp

然后我得到这个编译错误:

In file included from /usr/include/c++/4.6/vector:61:0,
                 from test.cpp:1:
/usr/include/c++/4.6/bits/stl_algobase.h: In function 'typename __gnu_cxx::__enable_if<(! std::__is_scalar<_Tp>::__value), void>::__type std::__fill_a(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = SomeStruct*, _Tp = SomeStruct, typename __gnu_cxx::__enable_if<(! std::__is_scalar<_Tp>::__value), void>::__type = void]':
/usr/include/c++/4.6/bits/stl_algobase.h:722:7:   instantiated from 'void std::fill(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = SomeStruct*, _Tp = SomeStruct]'
/usr/include/c++/4.6/bits/vector.tcc:397:5:   instantiated from 'void std::vector<_Tp, _Alloc>::_M_fill_insert(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = SomeStruct, _Alloc = std::allocator<SomeStruct>, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<SomeStruct*, std::vector<SomeStruct> >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = SomeStruct*, std::vector<_Tp, _Alloc>::size_type = long unsigned int, std::vector<_Tp, _Alloc>::value_type = SomeStruct]'
/usr/include/c++/4.6/bits/stl_vector.h:944:9:   instantiated from 'void std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = SomeStruct, _Alloc = std::allocator<SomeStruct>, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<SomeStruct*, std::vector<SomeStruct> >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = SomeStruct*, std::vector<_Tp, _Alloc>::size_type = long unsigned int, std::vector<_Tp, _Alloc>::value_type = SomeStruct]'
/usr/include/c++/4.6/bits/stl_vector.h:632:4:   instantiated from 'void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type, std::vector<_Tp, _Alloc>::value_type) [with _Tp = SomeStruct, _Alloc = std::allocator<SomeStruct>, std::vector<_Tp, _Alloc>::size_type = long unsigned int, std::vector<_Tp, _Alloc>::value_type = SomeStruct]'
test.cpp:12:18:   instantiated from here
/usr/include/c++/4.6/bits/stl_algobase.h:676:2: error: no match for 'operator=' in '* __first = __value'
/usr/include/c++/4.6/bits/stl_algobase.h:676:2: note: candidate is:
test.cpp:5:8: note: SomeStruct& SomeStruct::operator=(SomeStruct&)
test.cpp:5:8: note:   no known conversion for argument 1 from 'const SomeStruct' to 'SomeStruct&'

在 gcc 中启用 C++11 支持时编译正常:

g++ -std=c++0x test.cpp

有人能解释一下为什么这只适用于 C++11 模式吗?

编辑:

使用 Vagrant 进行复制的步骤:

vagrant init precise64
vagrant up
vagrant ssh
sudo apt-get install -y build-essential libboost1.48-all-dev
echo "#include <vector>
#include <map>
#include <boost/unordered_map.hpp>

struct SomeStruct {
  boost::unordered_map<int, int> intMap;
};

int main(int argc, const char* argv[]) {
  std::vector<SomeStruct> vals;

  vals.resize(100);
}" > test.cpp
g++ test.cpp

【问题讨论】:

  • 我无法在 gcc 4.6.3 或 4.8、ubuntu 12.04 64 位和 boost 1.46 上重现此问题。
  • MinGW下使用gcc 4.7.0和boost 1.49没有错误,用-std=c++03编译
  • 对不起,这是 boost 1.48 而不是 1.46。使用 Vagrant 重现的步骤:vagrant init precise64; vagrant up; vagrant ssh; sudo apt-get install -y build-essential libboost1.48-all-dev; echo "#include &lt;vector&gt; #include &lt;map&gt; #include &lt;boost/unordered_map.hpp&gt; struct SomeStruct { boost::unordered_map&lt;int, int&gt; intMap; }; int main(int argc, const char* argv[]) { std::vector&lt;SomeStruct&gt; vals; vals.resize(100); }" &gt; test.cpp; g++ test.cpp
  • 尝试注释掉std::vector::resize这一行。
  • @bamboon 代码编译良好,调整大小行被注释掉。

标签: c++ gcc boost stl c++11


【解决方案1】:

boost::unordered_map 的复制赋值运算符声明为:

unordered_map& operator=(unordered_map &t)

这反过来导致 (C++98 12.8 [#10]) SomeStruct 的隐式复制赋值运算符被声明为:

SomeStruct &operator= (SomeStruct &);

添加显式复制赋值运算符

SomeStruct &operator= (const SomeStruct &x) { intMap = x.intMap; return *this; }

解决了这个问题,它通过调用 unordered_map::operator= 的不同重载来工作。

此问题已在 Boost 1.52 中修复。它将运算符声明为:

unordered_map& operator=(unordered_map const& x);

【讨论】:

  • 你的显式复制分配会编译吗? intMap = x.intMap 应该失败 - x.intMap 在这里是 const,因此不会找到无序映射的适当复制分配重载。
  • @Basilevs,operator= - unordered_map&amp; operator=(const ::boost::rv&lt; unordered_map &gt;&amp; x) 的另一个重载,我在上面提到过。
  • @chill:谢谢,添加复制赋值运算符非常棒!
猜你喜欢
  • 1970-01-01
  • 2012-05-08
  • 2011-04-27
  • 1970-01-01
  • 2018-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多