比较两个map :: iterators:为什么需要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
is,gcc version 4.9.0 20140302(experimental)(GCC):
ali @ X230:〜/ tmp $〜/ gcc / install / bin / g ++ -std = c ++ 11 cctor.cpp
在/ home / ali / gcc / install / include / 4.9.0 / bits / stl_algobase.h:64:0,
从/home/ali/gcc/install/include/c++/4.9.0/bits/stl_tree.h:61,
从/ home / ali / gcc / install / include / c ++ / 4.9.0 / map:60,
来自cctor.cpp:1:
/home/ali/gcc/install/include/c++/4.9。 0 / bits / stl_pair.h:'struct std :: pair'的实例化:
cctor.cpp:9:31:从这里需要
/ 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]'声明接受const引用,但隐式声明将采取非const
constexpr pair(const pair&)= default;
^
包含clang版本3.5(trunk 202594)
ali @ X230:〜/ tmp $ clang ++ -Weverything -std = c ++ 11 cctor.cpp
在cctor.cpp包含的文件中:1:
在包括的文件中/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/map:60:
在包含在/ usr / lib / gcc / x86_64-linux-gnu / 4.7 /../../../../ include / c ++ / 4.7 / bits / stl_tree.h:63:
在/ 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:这个显式默认的拷贝构造函数的参数是const,但
a成员或基础要求它是非const
constexpr pair(const pair&)= default;
^
cctor.cpp:9:22:注意:在模板类的实例化'std :: pair'请求这里
return m.begin()== m.end(); // line 9
^
生成了1个错误。
我一直在查看
bits / stl_tree.h
不明白为什么它试图实例化std :: pair
。
为什么需要C ++ 11中的
std :: pair
的复制构造函数? / strong>
注意:上述代码是从在不可复制地图的地图迭代器上不支持等于运算符(==)。
解决方案
这里有两个不幸的问题。
质量差的错误消息:第8行应该已经给出编译错误,虽然错误消息只是抱怨第9行。在第8行得到一个错误将是相当有帮助,了解真正的问题将更容易。
另一个问题是 ecatmur 写。考虑下面的代码:
struct A {
A()
A(A&); //< - const missing
};
template< class T>
struct B {
B()= default;
B(const B&)= default;
T t;
};
int main(){
B< A> b;
}
无法编译。即使复制构造函数不需要在任何地方,它仍然实例化,因为它是默认的inline,在类的主体;这导致编译错误。这可以通过将复制构造函数移出类的主体来修复:
template< class T&
struct B {
B()= default;
B(const B&);
T t;
};
template< class T>
B< T> :: B(const B&)= default;
一切正常。不幸的是,
std :: pair
有一个默认定义的内联拷贝构造函数。解决方案p>
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节)复制构造函数默认定义inline:
constexpr pair(const pair&)=
The very simple code below compiles and links without a warning in C++98 but gives an incomprehensible compile error in C++11 mode.
#include <map> struct A { A(A& ); // <-- const missing }; int main() { std::map<int, A> m; return m.begin() == m.end(); // line 9 }
The error with
-std=c++11
is, gcc version 4.9.0 20140302 (experimental) (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; ^with clang version 3.5 (trunk 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.I have been looking at the code in
bits/stl_tree.h
and I don't understand why it is trying to instantiatestd::pair
.Why does it need the copy constructor of
std::pair
in C++11?
Note: the above code was extracted from Equality operator (==) unsupported on map iterators for non-copyable maps.
SOLUTION
There are two unfortunate issues here.
Poor quality error messages: Line 8 should already give a compile error although the error messages are only complaining about line 9 . Getting an error on line 8 would be quite helpful and understanding the real problem would be much easier. I will probably submit a bug report / feature request if this issue is still present in gcc / clang trunk.
The other issue is what ecatmur writes. Consider the following code:
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; }
It fails to compile. Even though the copy constructor is not needed anywhere, it is still instantiated because it is defaulted inline, in the body of the class; this leads to the compile error. This can be fixed by moving the copy constructor out of the body of the class:
template<class T> struct B { B() = default; B(const B& ); T t; }; template <class T> B<T>::B(const B& ) = default;
Everything is OK then. Unfortunately,
std::pair
has a default defined inline copy constructor.解决方案The copy constructor of
std::pair
isn't needed in this case, but because it is default defined inline in the declaration ofstd::pair
, it is automatically instantiated along with the instantiation ofstd::pair
itself.It would be possible for the standard library to provide a non-inline default definition of the copy constructor:
template<class _T1, class _T2> struct pair { // ... constexpr pair(const pair&); // ... }; // ... template<class _T1, class _T2> constexpr pair<_T1, _T2>::pair(const pair&) = default;
However this would not accord with the strict letter of the standard (clause 20.3.2), where the copy constructor is default defined inline:
constexpr pair(const pair&) = default;
这篇关于比较两个map :: iterators:为什么需要std :: pair的复制构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!