views:

175

answers:

1

I'm currently porting a heap of code that has previously only been compiled with Visual Studio 2008. In this code, there's an arrangement like this:

template <typename T> 
T convert( const char * s )
{
    // slow catch-all
    std::istringstream is( s );
    T ret;
    is >> ret;
    return ret; 
}

template <typename T, typename T2>
T convert( T2 * s )
{
    return convert<T>( static_cast<const char*>( s ));
}

template <typename T, typename T2>
T convert( T2 s )
{
    return T( s );
}

template <>
inline int convert<int>( const char * s )
{
    return (int)atoi( s );
}

Generally, there are a lot of specializations of the templated function with different return types that are invoked like this:

int i = convert<int>( szInt );

The problem is, that these template specializations result in "Ambiguous template specialization". If it was something besides the return type that differentiated these function specializations, I could obviously just use overloads, but that's not an option.

How do I solve this without having to change all the places the convert functions are called?

Update I added these two catch-all template specializations that I omitted the first time around. I am embarassed to say, I am unsure about the motivation for the second one, but the first one is due to the convert function being used a lot of places where string data is passed as a void *. I am unable to check it with GCC right now, but I suspect that these might be the problem.

Update 2 Here's the complete cpp file that will reproduce this. If you remove both of the "general purpose" functions, it will compile. If you let either of them stay, the ambiguous template specialization error will result.

#include <iostream>
#include <sstream>

template <typename T> 
T convert( const char * s )
{
    // this is a slow slow general purpose catch all, if no specialization is provided
    std::istringstream is( s );
    T ret;
    is >> ret;
    return ret; 
}

// general purpose 1
template <typename T, typename T2>
T convert( T2 * s )
{
    return convert<T>( static_cast<const char*>( s ));
}

// general purpose 2
template <typename T, typename T2>
T convert( T2 s )
{
    return T( s );
}

// Type specialized

template <>
inline float convert<float>( const char * s )
{
    return (float)atof( s );
}

int main( int argc, const char * sz[] )
{
    return 0;
}
+1  A: 

Apparently return convert<T>( static_cast<const char*>( s )); (or something else I can't see) is inducing the compiler to create a template instantiation of T convert( const char * s ) for T=float. Then when you try to specialize it later, it fails because the template version already exists.

When I moved the inline float convert<float>( const char * s ) before the general purpose converters (immediately after the const char* template function), I was able to compile successfully with g++ 4.2.

Mark B
A variation of that worked for me as well - you are spot on with the "something you can't see" - it's one of the bits of code that uses the template, which uses it with T=float at one point.Thanks a bunch.
Setien