[英]Comparing two map::iterators: why does it need the copy constructor of 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
的錯誤是,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; ^
與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.
我一直在看bits/stl_tree.h
中的代碼,我不明白為什么它試圖實例化std::pair
。
為什么在C ++ 11中需要std::pair
的拷貝構造函數?
注意:上面的代碼是從不可復制映射的映射迭代器上不支持的Equality運算符(==)中提取的。
解
這里有兩個不幸的問題。
質量差的錯誤消息:第8行應該已經給出了編譯錯誤,盡管錯誤消息只是抱怨第9行。 在第8行獲得錯誤將非常有幫助,理解真正的問題會容易得多。 如果gcc / clang trunk中仍然存在此問題,我可能會提交錯誤報告/功能請求。
另一個問題是ecatmur所寫的內容。 請考慮以下代碼:
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;
}
它無法編譯。 即使復制構造函數在任何地方都不需要,它仍然被實例化,因為它在類的主體中是內聯的默認值; 這導致編譯錯誤。 這可以通過將復制構造函數移出類的主體來修復:
template<class T>
struct B {
B() = default;
B(const B& );
T t;
};
template <class T>
B<T>::B(const B& ) = default;
一切都好。 不幸的是, std::pair
有一個默認定義的內聯拷貝構造函數。
在這種情況下, 不需要 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節),其中復制構造函數是默認的內聯定義:
constexpr pair(const pair&) = default;
我想我在嘗試減少錯誤后找到了它。 首先,似乎不需要進行比較以使程序格式錯誤。 然后,錯誤消息包含dtor,所以我嘗試不實例化dtor。 結果:
#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
}
但是輸出消息仍然包含,現在對於調用m
的ctor的行:
錯誤:此顯式默認的復制構造函數的參數是const,但成員或基礎要求它是非const
constexpr pair(const pair&) = default;
哪個提示[dcl.fct.def.default] / 4
用戶提供的顯式默認函數(即,在第一次聲明后顯式默認)是在明確默認的位置定義的; 如果將這樣的函數隱式定義為已刪除,則該程序格式錯誤 。
[強調我的]
如果,我認為,[class.copy] / 11表示,該構造函數應該定義為刪除,然后根據立即刪除它的定義-不僅在它的ODR使用。 因此,不應該要求實例化使程序格式錯誤。
std::map
使用std::pair
來存儲鍵值對,其中鍵(第一個元素)是const
。
編譯器錯誤與std::pair
所需的拷貝構造函數有關,即使它沒有被使用(我認為它不是這樣)。
必須生成std::pair<int, A>
。 這是調用map :: begin時首先需要的。 由於沒有為此類型指定顯式復制構造函數,因此使用了隱式復制構造函數。
只有當 T的所有非靜態成員(類型S)都具有復制構造函數S :: S(const S&)時,隱式構造函數才會具有簽名T :: T(const T&)(對於T的基礎必須保持相同的要求)類型復制構造函數)。 否則,使用具有簽名T :: T(T&)的復制構造函數。
A的復制構造函數不符合此要求,因此std :: pair :: pair具有錯誤的STL簽名,這需要T :: T(const T&)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.