C++/CLI 템플릿 클래스에서 연산자 오버로딩 문제를 해결하는 간단한 방법을 소개할까 합니다. 아래 코드는 원문에서 베껴온 코드이고, 언급했다시피 결과는 이상하게도 성공, 실패 입니다.

// LibraryA.cpp : library file.
#include "stdafx.h"
#include <iostream>

using namespace System;

template<typename ABC>
public ref class ManagedClassA 
{
public:
    int V;

    ManagedClassA(int v)
    {
        V = v;
    }

    static bool operator == (ManagedClassA^ a, ManagedClassA^ b)
    {
        // Return true if the fields match:
        return ( (a->V + b->V) % 2 == 0 );
    }

    static bool operator != (ManagedClassA^ a, ManagedClassA^ b)
    {
        return !(a == b);
    }
};

public ref class ManagedClassB : public ManagedClassA<int>
{
public:
    ManagedClassB(int v)
        : ManagedClassA(v)
    {
    }
};

// 단순 테스트용 클래스
public ref class Tester
{
public:
    static void Test1()
    {
        ManagedClassB^ b1 = gcnew ManagedClassB(1);
        ManagedClassB^ b2 = gcnew ManagedClassB(3);
        if(b1 == b2)
            System::Console::WriteLine("성공");
        else
            System::Console::WriteLine("실패");
    }
};


template<typename ABC>
public ref class ManagedClassC 
{
public:
    int V;

    ManagedClassC(int v)
    {
        V = v;
    }

    static bool operator == (ManagedClassC^ a, ManagedClassC^ b)
    {
        // Return true if the fields match:
        return ( (a->V + b->V) % 2 == 0 );
    }

    static bool operator != (ManagedClassC^ a, ManagedClassC^ b)
    {
        return !(a == b);
    }
};

public ref class ManagedClassD : public ManagedClassC<int>
{
public:
    ManagedClassD(int v)
        : ManagedClassC(v)
    {
    }
};
// LibraryB.cpp : main project file.
#include "stdafx.h"

using namespace System;

void Test2()
{
    ManagedClassD^ b1 = gcnew ManagedClassD(1);
    ManagedClassD^ b2 = gcnew ManagedClassD(3);
    if(b1 == b2)
        System::Console::WriteLine("성공");
    else
        System::Console::WriteLine("실패");
}

int main(array<System::String ^> ^args)
{
    Tester::Test1();
    Test2();
    return 0;
}

아무래도 컴파일러 또는 링커 버그 같지만 확신은 못하겠군요. 어쨌거나 이 문제를 가볍게 회피하는 수단을 삽질 끝에 찾아냈습니다. 연산자 오버로딩을 이렇게 바꾸면 됩니다.

template<typename ABC>
public ref class ManagedClassC 
{
public:
    int V;

    ManagedClassC(int v)
    {
        V = v;
    }

    virtual bool operator == (ManagedClassC^ b)
    {
        // Return true if the fields match:
        return ( (this->V + b->V) % 2 == 0 );
    }

    virtual bool operator == (ManagedClassC^ b)
    {
        return !(a == b);
    }
};

주의해 볼 곳은 virtual 키워드입니다. 재정의 가능한 메서드로 선언함으로써 컴파일러(또는 링커)가 지멋대로 메서드를 빼먹지 못하게 할 수 있는 것 같습니다. 참고로 연산자 == 는 맨처음 코드처럼 static으로 선언해도 되고, 위의 코드처럼 멤버 함수로 선언해도 됩니다. 만약 static으로 선언하고 싶다면 다음 코드처럼 고쳐야 합니다.

template<typename ABC>
public ref class ManagedClassC 
{
public:
    int V;

    ManagedClassC(int v)
    {
        V = v;
    }

    static bool operator == (ManagedClassC^ a, ManagedClassC^ b)
    {
        // Return true if the fields match:
        return ( (a->V + b->V) % 2 == 0 );
    }

    static bool operator != (ManagedClassC^ a, ManagedClassC^ b)
    {
        return !(a == b);
    }

    virtual bool ReferenceEquals(ManagedClassC^ that)
    {
        return ManagedClassC::operator == (this, that);
    }

    virtual bool ReferenceNotEquals(ManagedClassC^ that)
    {
        return ManagedClassC::operator != (this, that);
    }
    
};