考虑以下代码:
#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'的构造函数
:first(std :: forward&lt; _U1&gt;(__ x)),second(__ y){}
^ ~~~
/ usr / include / c ++ / 4.6 / bits / stl_pair.h:267:14:注意:在实例化中 函数模板特化'std :: pair, Foo&gt; :: pair,void&gt;'请求
return __pair_type(std :: forward&lt; _T1&gt;(__ x),std :: forward&lt; _T2&gt;(__ y));
^
/ usr / include / c ++ / 4.6 / bits / stl_map.h:467:29:注意:在实例化中 功能模板专业化 'std :: make_pair,Foo&gt;'请求
__ i = insert(__ i,std :: make_pair(std :: move(__ k),mapped_type()));
^
21:注意:在成员函数'std :: map,Foo的实例化中, std :: less&gt ;,std :: allocator,Foo&gt; &GT; &gt; :: operator []'在这里请求
M [ “富”] DoFoo();
似乎std::pair
的构造函数正在尝试使用Foo
的复制构造函数,我认为这是公平的,因为Foo
没有声明移动构造函数。正如我所料,提供(默认)移动构造函数可以解决问题。
但是,如果使用的libstdc++
版本为4.8或更高版本,则编译成功时不会定义移动构造函数。我确信在两种情况下编译器都是相同的,只有libstdc++
版本有所不同。 Foo(Foo&&) = delete;
也不会影响clang在这种情况下正确编译的能力。
我的问题有几个方面:
为什么旧版本的libstdc++
要求移动构造函数是用户提供的,以便使用它而不是复制构造函数?
在较新版本的库中有什么不同,它允许它创建新元素(根据operator[]
的合同)而没有任何移动/复制构造函数或operator=
?
哪个实施符合要求?如果有的话,标准对std::map<K, V>::mapped_type
的评价是什么?
答案 0 :(得分:3)
在C ++ 11中,[map.access]读取:
T& operator[](const key_type& x);
1 效果:如果地图中没有等效于
x
的键,请将value_type(x, T())
插入地图。2 需要:
key_type
应为CopyInsertable,mapped_type
为DefaultInsertable *此。3 返回:对* this中x对应的mapped_type的引用。
4 复杂性:对数。
operator[]
mapped_type
上的唯一要求是它是DefaultInsertable(基本上是DefaultConstructible)。如果库不支持带有mapped_type
的不可复制operator[]
,那么这是一个错误。