Comparing two map::iterators: why does it need the copy constructor of std::pair?

前端 未结 3 969
闹比i
闹比i 2021-02-04 03:35

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          


        
相关标签:
3条回答
  • 2021-02-04 04:21

    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&).

    0 讨论(0)
  • 2021-02-04 04:35

    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;
    
    0 讨论(0)
  • 2021-02-04 04:37

    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.

    0 讨论(0)
提交回复
热议问题