比较两个map::迭代器:为什么需要std::pair的复制构造函数
Comparing two map::iterators: why does it need the copy constructor of std::pair?
下面这个非常简单的代码在c++ 98中编译和链接时没有警告,但是在c++ 11模式下给出了一个难以理解的编译错误。
#include <map>
struct A {
A(A& ); // <-- const missing
};
int main() {
std::map<int, A> m;
return m.begin() == m.end(); // line 9
}
-std=c++11
的错误是,gcc版本4.9.0 20140302(实验)(gcc):
使用clang版本3.5 (trunk 202594)
<>之前ali@X230:~/tmp$ clang++ - everything -std=c++11 cctor.cpp . net在文件中包含从cctor.cpp:1:在文件包含从/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../包括/c++/4.7/地图:60:在文件包含从/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../包括/c++/4.7/位/stl_tree.h: 63:在文件包含从/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../包括/c++/4.7/位/stl_algobase.h: 65:/usr/lib/gcc/x86_64-linux-gnu/4.7/…/…/…//include/c++/4.7/bits/stl_pair.h:119:17: error:这个显式默认的复制构造函数的参数是const,但是成员或基类型要求其为非const类型const pair(const pair&) = default;^Cctor.cpp:9:22:注意:在这里请求的模板类std::pair的实例化中返回m.s begin() == m.s end();//第9行^1 .产生错误。>之前我一直在看bits/stl_tree.h
中的代码,我不明白为什么它试图实例化std::pair
。
为什么在c++ 11中需要std::pair
的复制构造函数?
注意:以上代码是从map迭代器上不支持的相等操作符(==)中提取的,用于不可复制的映射。
<
解决方案/strong>
这里有两个不幸的问题。
质量差的错误消息:第8行应该已经给出了编译错误,尽管错误消息只抱怨第9行。在第8行获得错误将非常有帮助,并且更容易理解真正的问题。如果这个问题在gcc/clang主干中仍然存在,我可能会提交一个bug报告/特性请求。
另一个问题是ecatmur写了什么。考虑下面的代码:
struct A {
A() = default;
A(A& ); // <-- const missing
};
template<class T>
struct B {
B() = default;
B(const B& ) = default;
T t;
};
int main() {
B<A> b;
}
编译失败。即使复制构造函数在任何地方都不需要,它仍然被实例化,因为它是默认的内联的,在类的主体中;这会导致编译错误。这可以通过将复制构造函数移出类体来修复:
template<class T>
struct B {
B() = default;
B(const B& );
T t;
};
template <class T>
B<T>::B(const B& ) = default;
那么一切都好了。不幸的是,std::pair
有一个默认定义的内联复制构造函数。
在本例中不需要 std::pair
的复制构造函数,但由于它是在std::pair
的声明中默认内联定义的,因此它将与std::pair
本身的实例化一起自动实例化。
标准库可以提供复制构造函数的非内联默认定义:
template<class _T1, class _T2>
struct pair
{
// ...
constexpr pair(const pair&);
// ...
};
// ...
template<class _T1, class _T2>
constexpr pair<_T1, _T2>::pair(const pair&) = default;
然而,这将不符合标准的严格字母(第20.3.2条),其中复制构造函数是默认定义的内联:
constexpr pair(const pair&) = default;
std::map
使用std::pair
存储键值对,其中键(第一个元素)为const
。
编译器错误与std::pair
所需的复制构造函数有关,即使它没有被使用(我认为它没有被使用)。
std::pair<int, A>
。这首先需要调用map::begin。由于此类型没有给出显式复制构造函数,因此使用隐式复制构造函数。
隐式构造函数只有在 T(类型S)的所有非静态成员都具有复制构造函数S::S(const &)时才具有签名T::T(const &) (对于T的基本类型复制构造函数,同样的要求也必须成立)。否则将使用签名为T::T(T&)的复制构造函数。
A的复制构造函数没有满足这个要求,因此std::pair::pair的STL签名错误,需要T::T(const T&)。
我想我是在尝试减少错误后发现的。首先,这种比较似乎并不会导致程序格式错误。然后,错误消息包含了dr,所以我尝试不实例化dr。结果:
#include <map>
struct A {
A(A& ); // <-- const missing
};
int main() {
std::map<int, A>* m = new std::map<int, A>();
// note: dtor not (necessarily?) instantiated
}
但是输出消息仍然包含,现在对于m
的ctor被调用的行:
error:这个显式默认复制构造函数的形参是const,但成员或基类要求它为非const
constexpr pair(const pair&) = default;
提示[dcl.fct.def.default]/4
用户提供的显式默认函数(即,在其第一次声明)是在显式默认的地方定义的;如果这样的函数被隐式定义为deleted,则程序是病态的。
(我强调)
如果,我认为,[类。Copy]/11说这个应该定义为已删除,然后它被定义为立即删除-不仅仅是当它被odr使用时。因此,不应该需要实例化来使程序格式不良。
- c++:在switch中使用std::pair的可能性
- 将从std::映射中获取的std::pair引用传递给接受std::对引用的函数
- Hash for a std::pair, for use in an unordered_map
- 类模板的参数太少 "std::pair":在函数中将 std 对作为参数传递
- 接收std :: Pair作为参数并从支撑列表初始化中推论的模板函数
- std::pair中的template-template参数
- std::experimental::ostream_joiner and std::pair
- 如何将两个std :: vector结合到一个std :: vector与std :: pair
- 错误 C2678:二进制'==':找不到采用 'std::pair<const _Kty,_Ty>' 型左操作数的运算符
- C++错误处理-使用std::pair或std::tuple返回错误代码和函数返回的缺点
- 将std::pair转换为具有任意数量元素的std::tuple
- 宏MOCK_METHOD传递了3个参数,但std::pair只接受了2个错误
- push_back std::pair into std::vector error
- 如何返回std::pair的内容
- 谷歌模拟成员函数中的std::pair参数编译失败
- 无法正确地向java绑定公开std::pair
- std::pair抱怨类型不完整
- std::pair的默认构造函数<>将基本类型(int等)设置为零
- Emplacing a std::pair
- 创建一个以std::pair为键的std::unordered_map