template と operator = を組み合わせてみたところ死亡(スペランカー先生のように)
ソース
#include <windows.h> #include <stdio.h> class A { public: A(int i = 0) : m(i) { puts("コンストラクタかしら"); } ~A() { puts("デストラクタかしら"); } A& operator = (const A& a) { this->m = a.m; puts("operator = かしら"); return *this; } int m; }; int main() { A a; a = A(10); return 0; }
実行結果
コンストラクタかしら コンストラクタかしら operator = かしら デストラクタかしら デストラクタかしら
ってのは、C++使う人なら誰でも予想できることです。
さて、コレをクラステンプレート化してみましょう。
ソース
#include <windows.h> #include <stdio.h> template<typename T> class A { public: A(T i = 0) : m(i) { puts("コンストラクタかしら"); } ~A() { puts("デストラクタかしら"); } template<typename U> A& operator = (const A<U>& a) { this->m = a.m; puts("operator = かしら"); return *this; } T m; }; int main() { typedef A<int> AINT; AINT a; a = AINT(10); return 0; }
実行結果
コンストラクタかしら コンストラクタかしら デストラクタかしら デストラクタかしら
operator = が呼ばれていないという脅威の事実!
えええ!? なんでなんで!? しっかり operator = 用意してあるじゃん! U と T として呼ばれないの? ってか、この子しっかりコピーできてるの? また VC7.1 のバグなんちゃうの!?
とか思ってみましたが、5分ぐらいしてようやく気づきました。 暗黙の operator = が呼ばれてるだけ じゃんと。
// ↓自前で用意した operator = template<typename U> A& operator = (const A<U>& a) { this->m = a.m; puts("operator = かしら"); return *this; } // ↓コンパイラが勝手に用意する operator = A& operator = (const A<T>& a) { 〜 }
型の一致度は、下の方が高いわけですから、そりゃコッチ呼ばれるわなぁー。
似たような問題が過去に
そういえば、コンストラクタでも同じ問題に遭遇した過去があったなぁーとか思い出してみたり。