Проблема "неоднозначной специализации шаблона" - PullRequest
3 голосов
/ 15 мая 2010

В настоящее время я портирую кучу кода, который ранее был скомпилирован только с 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 используется во многих местах, где строковые данные передаются как пустота *. Сейчас я не могу проверить это в 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;
}

1 Ответ

1 голос
/ 27 мая 2010

Очевидно, 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.

...