Thursday, February 8, 2018

c++ - Comparing two map::iterators: why does it need the copy constructor of std::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 

struct A {
A(A& ); // <-- const missing
};

int main() {
std::map 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 instantiate std::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

struct B {
B() = default;
B(const B& ) = default;
T t;
};

int main() {
B 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
struct B {
B() = default;
B(const B& );
T t;
};


template
B::B(const B& ) = default;


Everything is OK then. Unfortunately, std::pair has a default defined inline copy constructor.


Answer



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
struct pair
{
// ...
constexpr pair(const pair&);
// ...
};
// ...
template
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;


No comments:

Post a Comment

plot explanation - Why did Peaches&#39; mom hang on the tree? - Movies &amp; TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...