Неоднозначная проблема специализации шаблона

В настоящее время я переношу кучу кода, который ранее был скомпилирован только с помощью Visual Studio 2008. В этом коде есть такое расположение:

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 );
}

Как правило, существует множество специализаций шаблонной функции с различными типами возвращаемого значения, которые вызываются следующим образом:

int i = convert<int>( szInt );

Проблема в том, что эти специализации шаблонов приводят к "неоднозначной специализации шаблона". Если бы эти специализации функций отличались чем-то другим, кроме типа возвращаемого значения, я, очевидно, мог бы просто использовать перегрузки, но это не выход.

Как мне решить эту проблему, не меняя все места, где вызываются функции преобразования?

Обновление Я добавил эти две универсальные специализации шаблонов, которые я пропустил в первый раз. Мне стыдно сказать, я не уверен в мотивации второго, но первый связан с тем, что функция convert используется во многих местах, где строковые данные передаются как void *. Я не могу проверить это с помощью GCC прямо сейчас, но я подозреваю, что это может быть проблемой.

Обновление 2 Вот полный файл cpp, который будет воспроизводить это. Если вы удалите обе функции «общего назначения», он скомпилируется. Если вы оставите любой из них, возникнет ошибка неоднозначной специализации шаблона.

#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;
}

person Setien    schedule 15.05.2010    source источник
comment
В коде должно быть что-то еще, чего вы не показываете в вопросе. В приведенном выше коде нет никакой двусмысленности, и я проверил, что он правильно компилируется с помощью g++ (i686-apple-darwin10-g++-4.2.1). Попробуйте придумать случай, когда вы видите двусмысленность, и отредактируйте вопрос.   -  person David Rodríguez - dribeas    schedule 15.05.2010
comment
если я правильно понимаю, это, возможно, уже сделано для вас: boost. org/doc/libs/1_43_0/libs/conversion/lexical_cast.htm   -  person Anycorn    schedule 15.05.2010
comment
Да, повторяя комментарий Дэвида Родригеса, можете ли вы привести минимальный пример, который воспроизводит проблему?   -  person Brooks Moses    schedule 15.05.2010
comment
Я сделаю это, как только окажусь рядом с Mac, на котором запущен проект — извините, что не сделал этого в первую очередь. Плохой тон.   -  person Setien    schedule 18.05.2010
comment
ааа, я не могу использовать boost, но спасибо за предложение.   -  person Setien    schedule 23.05.2010
comment
Я не совсем уверен, как работает система оповещения о переполнении стека, поэтому я также оставлю здесь комментарий: я обновил основной пост, и теперь он включает минимальный пример, который вызовет эту ошибку.   -  person Setien    schedule 23.05.2010


Ответы (1)


Очевидно, return convert<T>( static_cast<const char*>( s )); (или что-то еще, чего я не вижу) побуждает компилятор создать экземпляр шаблона T convert( const char * s ) для T=float. Затем, когда вы попытаетесь специализировать его позже, это не удастся, потому что версия шаблона уже существует.

Когда я переместил inline float convert<float>( const char * s ) перед конвертерами общего назначения (сразу после функции шаблона const char*), я смог успешно скомпилировать с g++ 4.2.

person Mark B    schedule 26.05.2010
comment
Вариант, который сработал и у меня — вы попали в точку с чем-то, чего не видите — это один из фрагментов кода, который использует шаблон, который использует его с T = float в одной точке. Огромное спасибо. - person Setien; 03.06.2010