tags:

views:

60

answers:

1

So given the following template functions with partial specialization

template<typename T>
void foo(vector<T> &in) {
    cout << "vector" << endl;
}

template<typename T>
void foo(T &in) {
    cout << "scalar" << endl;
}

int main(int arc, char *argv[]) {
    vector<double> a;
    double b;

    foo(a);
    foo(b);
    return 0;
}

I have no problem compiling with g++ 3.4.6 and get the expected output:

vector
scalar

Now, if I add a second template parameter:

template<class U, typename T>
void foo2(vector<T> &in) {
    U a;
    cout << "vector" << endl;
}

template<class U, typename T>
void foo2(T &in) {
    U a;
    cout << "scalar" << endl;
}

and call it with the following:

int main(int arc, char *argv[]) {
    vector<double> a;
    double b;

    foo2<double>(a);
    foo2<double>(b);
    return 0;
}

When I try to compile it GCC 3.4.6 gives me an ambiguous overload error.

error: call of overloaded `foo2(std::vector<double, std::allocator<double> >&)' is ambiguous
note: candidates are: void foo2(std::vector<T, std::allocator<_T2> >&) [with U = double, T = double]
note:                 void foo2(T&) [with U = double, T = std::vector<double, std::allocator<double> >]

I fail to see how the second template parameter now makes the overload ambiguous. As far as I can tell the vector version should still be more specialized. Is this just a bug in 3.4? Is there a workaround?

For the record the code works in gcc 4.1 without issue. Unfortunately some of our tools are still tied to 3.4 so that upgrading isn't the solution.

Thanks.

+2  A: 

This seems to be related to this defect which is fixed in the latest version of the compiler. Workarounds are to explicitly set all arguments of the template or to use functor instead:

template<typename U>
struct foo2 {
    template<typename T>
    void operator()( std::vector<T> &in ) {
        U a;
        cout << "vector" << endl;
    }
    template<typename T>
    void operator()( T& in ) {
        U a;
        cout << "scalar" << endl;
    }
};

int main(int arc, char *argv[]) {
    vector<double> a;
    double b;

    foo2<double>()(a);
    foo2<double>()(b);
    return 0;
}
Kirill V. Lyadvinsky
Thank you. I saw that bug report during my searches but it didn't really give me a work around. Using the functor seems to have solved my problem though. Again, thanks.
asinclair