简体   繁体   English

比较两个map :: iterators:为什么需要std :: pair的拷贝构造函数?

[英]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. 下面非常简单的代码在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
}

The error with -std=c++11 is, gcc version 4.9.0 20140302 (experimental) (GCC): -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;
                 ^

with clang version 3.5 (trunk 202594) 与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.

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 . 我一直在看bits/stl_tree.h中的代码,我不明白为什么它试图实例化std::pair

Why does it need the copy constructor of std::pair in C++11? 为什么在C ++ 11中需要std::pair的拷贝构造函数?


Note: the above code was extracted from Equality operator (==) unsupported on map iterators for non-copyable maps . 注意:上面的代码是从不可复制映射的映射迭代器上不支持的Equality运算符(==)中提取的。


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 . 质量差的错误消息:第8行应该已经给出了编译错误,尽管错误消息只是抱怨第9行。 Getting an error on line 8 would be quite helpful and understanding the real problem would be much easier. 在第8行获得错误将非常有帮助,理解真正的问题会容易得多。 I will probably submit a bug report / feature request if this issue is still present in gcc / clang trunk. 如果gcc / clang trunk中仍然存在此问题,我可能会提交错误报告/功能请求。

The other issue is what ecatmur writes. 另一个问题是ecatmur所写的内容。 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. 不幸的是, std::pair有一个默认定义的内联拷贝构造函数。

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. 在这种情况下, 不需要 std::pair的复制构造函数,但由于它是在std::pair的声明中默认定义的内联,因此它会与std::pair本身的实例化一起自动实例化。

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: 但是,这不符合标准的严格字母(第20.3.2节),其中复制构造函数是默认的内联定义:

  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. 然后,错误消息包含dtor,所以我尝试不实例化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: 但是输出消息仍然包含,现在对于调用m的ctor的行:

error: the parameter for this explicitly-defaulted copy constructor is const, but a member or base requires it to be non-const 错误:此显式默认的复制构造函数的参数是const,但成员或基础要求它是非const

  constexpr pair(const pair&) = default; 

Which hints to [dcl.fct.def.default]/4 哪个提示[dcl.fct.def.default] / 4

A user-provided explicitly-defaulted function (ie, 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. 如果,我认为,[class.copy] / 11表示,该构造函数应该定义为删除,然后根据立即删除它的定义-不仅在它的ODR使用。 Therefore, an instantiation shouldn't be required to make the program ill-formed. 因此,不应该要求实例化使程序格式错误。

std::map uses std::pair to store key-value pairs, where the key (the first element) is const . std::map使用std::pair来存储键值对,其中键(第一个元素)是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所需的拷贝构造函数有关,即使它没有被使用(我认为它不是这样)。

std::pair<int, A> has to be generated. 必须生成std::pair<int, A> This is first required with the call to map::begin. 这是调用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). 只有当 T的所有非静态成员(类型S)都具有复制构造函数S :: S(const S&)时,隐式构造函数才会具有签名T :: T(const T&)(对于T的基础必须保持相同的要求)类型复制构造函数)。 Otherwise a copy constructor with signature T::T(T&) is used instead. 否则,使用具有签名T :: T(T&)的复制构造函数。

A's copy constructor fails this requirement, so std::pair::pair has the wrong signature for the STL, which requires T::T(const T&). A的复制构造函数不符合此要求,因此std :: pair :: pair具有错误的STL签名,这需要T :: T(const T&)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么std :: map emplace需要在gcc上使用复制构造函数? - Why does std::map emplace need a copy constructor on gcc? 为什么C ++允许类型为std :: map而没有默认构造函数而不是std :: pair? - Why does C++ allow type has no-default constructor for std::map while not std::pair? std :: vector构造函数接受迭代器对 - std::vector constructor taking pair of iterators 为什么std :: map :: const_iterator在std :: for_each期间调用std :: pair构造函数,但是一个简单的for循环却没有? - Why does std::map::const_iterator call the std::pair constructor during a std::for_each, but a simple for loop does not? 为什么`std :: pair <int, movable> `需要一个[删除]`const&`复制构造函数? - Why does `std::pair<int, movable>` require a [deleted] `const&` copy constructor? 为什么std :: map需要一对? - why does std::map take a pair? 为什么std :: pair没有迭代器? - Why doesn't std::pair have iterators? C ++ std :: map和std :: set是否会删除副本值,从而使迭代器无效 - Does C++ std::map and std::set erase copy values and thus invalidate iterators Class 与 std::map object 和删除的复制分配和构造函数导致 C2280 与 std::pair 的复制构造函数 - Class with std::map object and deleted copy assignment and constructor causes C2280 with std::pair's copy constructor 为什么std :: map接受std :: pair作为键,但std :: unordered_map不接受? - Why does std::map accept a std::pair as key, but std::unordered_map does not?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM