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
std::map
uses std::pair
to store key-value pairs, where the key (the first element) is const
.
The compiler error relates to the required copy constructor for std::pair
, even if it isn't being used (which I don't think it is).
std::pair<int, A>
has to be generated. This is first required with the call to map::begin.
Since no explicit copy constructor is given for this type, the implicit one used.
The implicit constructor will have signature T::T(const T&) only if all non-static members of T, (type S), have copy constructors S::S(const S&) (the same requirement has to hold for T's base types copy constructors). Otherwise a copy constructor with signature T::T(T&) is used instead.
A's copy constructor fails this requirement, so std::pair::pair has the wrong signature for the STL, which requires T::T(const T&).
The copy constructor of std::pair
isn't needed in this case, but because it is default defined inline in the declaration of std::pair
, it is automatically instantiated along with the instantiation of std::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;
I think I found it after trying to reduce the error. First, the comparison doesn't seem required to make the program ill-formed. Then, the error message contained the dtor, so I tried not to instantiate the dtor. Result:
#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
}
But the output message still contains, now for the line where the ctor of m
is called:
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;
Which hints to [dcl.fct.def.default]/4
A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed.
[emphasis mine]
If, as I assume, [class.copy]/11 says that this ctor should be defined as deleted, then it is defined as deleted immediately - not only when it's odr-used. Therefore, an instantiation shouldn't be required to make the program ill-formed.