【发布时间】:2015-07-10 17:50:16
【问题描述】:
考虑这段代码:
#include <iostream>
#include <map>
#include <string>
using namespace std;
class Foo {
public:
Foo() {}
virtual ~Foo() {}
void DoFoo() { cout << "Foo" << endl; }
Foo(const Foo&) = delete;
void operator=(const Foo&) = delete;
};
int main() {
map<string, Foo> m;
m["Foo"].DoFoo();
}
g++ 和 clang++ 在使用早于 4.8 的 libstdc++ 版本时编译失败。 clang++ 吐出的确切错误信息是:
在 /usr/include/c++/4.6/iostream:39 包含的文件中:
在 /usr/include/c++/4.6/ostream:39 中包含的文件中:
在 /usr/include/c++/4.6/ios:40 包含的文件中:
在 /usr/include/c++/4.6/bits/char_traits.h:40 包含的文件中:
在 /usr/include/c++/4.6/bits/stl_algobase.h:65 包含的文件中:
/usr/include/c++/4.6/bits/stl_pair.h:121:35:错误:调用已删除 'Foo'的构造函数
: 第一个(std::forward<_u1>(__x)), 第二个(__y) { }
^~~~
/usr/include/c++/4.6/bits/stl_pair.h:267:14:注意:在实例化 函数模板特化 'std::pair, Foo>::pair, void>' 在这里请求
return __pair_type(std::forward<_t1>(__x), std::forward<_t2>(__y));
^
/usr/include/c++/4.6/bits/stl_map.h:467:29:注意:在实例化 函数模板特化 'std::make_pair, Foo>' 在这里请求
__i = insert(__i, std::make_pair(std::move(__k), mapped_type()));
^
21 : 注意: 在成员函数 'std::map, Foo, std::less >, std::allocator, Foo> > >::operator[]' 在这里请求
m["Foo"].DoFoo();
似乎std::pair 的构造函数正在尝试使用Foo 的复制构造函数,我想这很公平,因为Foo 没有声明移动构造函数。正如我所料,提供(默认)移动构造函数可以解决问题。
但是,当使用的 libstdc++ 版本为 4.8 或更高版本时,编译成功而无需定义移动构造函数。我相信编译器在这两种情况下都是相同的,只有libstdc++ 版本不同。 Foo(Foo&&) = delete; 在这种情况下也不会影响 clang 正确编译的能力。
我的问题有几个方面:
为什么旧版本的libstdc++ 需要用户提供移动构造函数才能使用它而不是复制构造函数?
较新版本的库有什么不同,允许它在没有任何移动/复制构造函数或operator= 的情况下创建新元素(根据operator[] 的合同)?
哪些实现符合要求?标准对std::map<K, V>::mapped_type 有什么看法(如果有的话)?
【问题讨论】:
-
23.2.4.7 has
The associative containers meet all the requirements of Allocator-aware containers (23.2.1), except that for map and multimap, the requirements placed on value_type in Table 96 apply instead to key_type and mapped_type. [ Note: For example, in some cases key_type and mapped_type are required to be CopyAssignable even though the associated value_type, pair<const key_type, mapped_type>, is not CopyAssignable. —end note ]可能是导致问题的原因。 -
@CoryKramer 似乎正在使用最近的
libstdc++,我知道它可以正常编译。 -
@NathanOliver 谢谢,我会试着去看看那里!注释指向较新版本的
libstdc++没有标准那么严格,不是吗?
标签: c++ c++11 standards standard-library