使用關聯容器map時遇到的一個問題(declared to take const reference, but implicit declaration would take non-const)
阿新 • • 發佈:2021-12-05
今天遇到一個問題,情形類似於這樣:
1 #include <iostream> 2 #include <map> 3 4 using namespace std; 5 6 struct A { 7 A() = default; 8 //A(int a); 9 A(A& ) = default; 10 }; 11 12 13 14 15 int main() { 16 map<int, A> m; 17 A a; 18 m[1] = a; 19 /* 第18行報錯:20 constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = A]’ declared to take const reference, but implicit declaration would take non-const 21 constexpr pair(const pair&) = default; 22 */ 23 }
實際上,如果沒有寫17,18行,問題在第16行就會報同樣的錯誤
原因和解決方法如下:
1 #include <iostream> 2 3 using namespace std; 4 5 struct A { 6 A() = default; 7 //A(int a); 8 A(A& ) = default; // <-- const missing (如果宣告為 A(const A& ) 就沒有問題) 9 }; 10 11 template<class T> 12 struct B { 13 B() = default; 14 B(const B& ) = default; //B<T>::B(const B<T>&) [with T = A]’ declared to take const reference, but implicit declaration would take non-const 類模板中的預設複製建構函式是內聯的 15 T t; 16 }; 17 18 /* template <class T> 19 B<T>::B(const B& ) = default; //如果不對A做改動,則需要把B的複製構函定義為非inline (這樣做實際上只是掩耳盜鈴。因為當我呼叫B的複製構函時仍會出問題) */ 20 21 int main() { 22 B<A> b; // 23 B<A> c(b); //採用將類模板的複製構函定義放到外面的方法時問題仍會出現 24 /* 第14行報錯: B<T>::B(const B<T>&) [with T = A]’ declared to take const reference, but implicit declaration would take non-const 25 B(const B& ) = default; 26 問題原因:第22行雖然沒有呼叫A的複製構函,但類模板的預設複製構函是inline的,所以在例項化的時候會預設生成B<T>的複製構函,而B的複製構函會將const T 作為入參呼叫A的複製構函,這與A的複製構函入參為非const衝突 27 */ 28 } 29 30 /* 31 1. 如果你定義了一個類模板,用別人的類來例項化時,如果別人的類複製構函入參不是const的(而你的類模板是const), 32 則可以把你的類模板預設複製構函的定義放到模板外面(因為預設是inline)(實際上這樣做問題仍存在,只要使用者程式碼呼叫B的複製構函時問題就會暴露), 33 或者乾脆你的類模板的複製構函入參也宣告為非const(這樣才真正解決問題) 34 2. 如果你定義了一個類,用別人的類模板並將這個類作為模板引數時,如果別人的模板的複製構函入參是const的,則你的類的複製構函也必須是const 35 3. 當你自己的類用作關聯容器的模板引數時,也必須把類複製構函的入參宣告為const (因為map的元素型別是模板類pair<>,pair的複製構函是入參為const的行內函數,如同上面的struct B) 36 */