tags:

views:

708

answers:

2

I have the following code:

#include <stdio.h>

template<int A>
class Thing
{ // 5
    public:
        Thing() :
            data(A) {
        }

        template<int B>
        Thing &operator=(const Thing<B> &other) {
            printf("operator=: A = %d; B = %d\n", A, B);
            printf("this->data = %d\n", data);
        }

    private:
        int data;
};

int main() {
    Thing<0> a, b;
    Thing<1> c;

    a = b;
    a = c;
    c = b;

    return 0;
}

I need to specialize Thing<A>::operator= for A == B. I have tried this:

template<int B>
template<int A>
Thing<A> &Thing<A>::template operator=(const Thing<A> &other) { // 23
    printf("operator= (specialized): A = %d; B = %d; A %c= B\n", A, B, (A == B) ? '=' : '!');
    printf("this->data = %d; other.data = %d\n", data, other.data);
}

However, I receive compile errors with g++:

23: error: invalid use of incomplete type ‘class Thing<B>’
 5: error: declaration of ‘class Thing<B>’

I have tried using an if(A == B) in operator= without a specialization. However, I receive errors for accessing the private member data, which I need to access where A == B.

How can I properly specialize my member function template operator= of the class template Thing?

+1  A: 

I don't think you need to specialize it, can't you just provide an overload for operator=?

template<int A>
class Thing
{ // 5
    public:
        Thing() :
            data(A) {
        }

        template<int B>
        Thing &operator=(const Thing<B> &other) {
            printf("operator=: A = %d; B = %d\n", A, B);
            printf("this->data = %d\n", data);
        }

        Thing &operator=(const Thing &other) {
            printf("operator overload called");
            printf("this->data = %d\n", data);
        }

    private:
        int data;
};

IIRC there are some lookup gotchas if you try to combine overloads with specializations, but that doesn't look necessary here.

Steve Jessop
I am ashamed I overlooked this completely. Many thanks!
strager
A: 

Yes, I think an overload should work fine, though there are some strange things that can happen due to the order in which parameters and templates are matched.

Just for completeness, here's how to make your original example compile:

template<int A>
class Thing
{ // 5
...
template<int B>
Thing<A> &operator=(const Thing<A> &);
};

template<int A>
template<int B>
Thing<A> &Thing<A>::operator=(const Thing<A> &other) { // 23
    ...
Tim Sylvester