比较两个map :: iterators:为什么需要std :: pair的复制构造函数? [英] Comparing two map::iterators: why does it need the copy constructor of std::pair?

查看:761
本文介绍了比较两个map :: iterators:为什么需要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 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<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 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;

这篇关于比较两个map :: iterators:为什么需要std :: pair的复制构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆