下面编译和链接的非常简单的代码,而无需用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):
ali@X230:~/tmp$ ~/gcc/install/bin/g++ -std=c++11 cctor.cpp
In file included from /home/ali/gcc/install/include/c++/4.9.0/bits/stl_algobase.h:64:0,
from /home/ali/gcc/install/include/c++/4.9.0/bits/stl_tree.h:61,
from /home/ali/gcc/install/include/c++/4.9.0/map:60,
from cctor.cpp:1:
/home/ali/gcc/install/include/c++/4.9.0/bits/stl_pair.h: In instantiation of ‘struct std::pair’:
cctor.cpp:9:31: required from here
/home/ali/gcc/install/include/c++/4.9.0/bits/stl_pair.h:127:17: error: ‘constexpr std::pair::pair(const std::pair&) [with _T1 = const int; _T2 = A]’ declared to take const reference, but implicit declaration would take non-const
constexpr pair(const pair&) = default;
^
与clang版本3.5(主干202594)
ali@X230:~/tmp$ clang++ -Weverything -std=c++11 cctor.cpp
In file included from cctor.cpp:1:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/map:60:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/stl_tree.h:63:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/stl_algobase.h:65:
/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/stl_pair.h:119:17: error: the parameter for this explicitly-defaulted copy constructor is const, but
a member or base requires it to be non-const
constexpr pair(const pair&) = default;
^
cctor.cpp:9:22: note: in instantiation of template class 'std::pair' requested here
return m.begin() == m.end(); // line 9
^
1 error generated.
我一直在寻找在 bits/stl_tree.h
的代码,我不明白为什么它试图实例 std::pair
.
Why does it need the copy constructor of std::pair in C++11?
注意:上面的代码从平等运算符(==)不支持的在 Map 上的迭代器不可复制 Map 萃取 .
SOLUTION
这里有两个不幸的问题 .
质量差的错误消息:第8行应该已经给出了编译错误,尽管错误消息只是抱怨第9行 . 在第8行获得错误将非常有帮助,理解真正的问题会容易得多 . 如果gcc / clang trunk中仍然存在此问题,我可能会提交错误报告/功能请求 .
另一个问题是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
有一个默认定义的内联复制构造函数 .
3 回答
在这种情况下,不需要
std::pair
的复制构造函数,但由于它是std::pair
声明中的内联默认定义,因此会自动实例化std::pair
本身的实例化 .标准库可以提供复制构造函数的非内联默认定义:
然而,这不会与标准(第20.3.2),其中的拷贝构造函数是默认定义内嵌的严格信一致:
我想我找到它试图减少错误之后 . 首先,似乎不需要进行比较以使程序格式错误 . 然后,错误消息包含dtor,所以我尝试不实例化dtor . 结果:
但是输出消息仍然包含,现在用于调用
m
的ctor的行:哪个提示[dcl.fct.def.default] / 4
[强调我的]
如果,正如我所假设的那样,[class.copy] / 11表示应该将此ctor定义为已删除,则将其定义为立即删除 - 不仅仅是在需要使程序格式错误时才需要删除 .
std::map
使用std::pair
来存储键值对,其中键(第一个元素)是const
.编译器错误涉及到需要复制构造
std::pair
,即使它不是't being used (which I don'认为这不是) .必须生成
std::pair<int, A>
. 这是调用map :: begin时首先需要的 . 由于没有为此类型指定显式复制构造函数,因此使用了隐式复制构造函数 .只有当T的所有非静态成员(类型S)都具有复制构造函数S :: S(const S&)时,隐式构造函数才会具有签名T :: T(const T&)(对于T的基础必须保持相同的要求)类型复制构造函数) . 否则,使用具有签名T :: T(T&)的复制构造函数 .
A的拷贝构造函数失败这一要求,所以性病::对::对对STL的,这需要T :: T(const的T&)签名错误 .