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)
{
    〜
}

型の一致度は、下の方が高いわけですから、そりゃコッチ呼ばれるわなぁー。

似たような問題が過去に

そういえば、コンストラクタでも同じ問題に遭遇した過去があったなぁーとか思い出してみたり。