C ++ Специализация функций не допускается? - PullRequest
1 голос
/ 04 января 2012

Вот очень простой пример специализации функций в C ++. Я думаю, что это должно работать, но компилятор Visual Studio дает мне сообщение о неоднозначности.

template <class T> T min(T a, T b) { 
    if(a < b) return a;
    else return b;
}

string min(string str1, string str2) { 
    if(str1.length() < str2.length()) return str1;
    return str2;
}


void main(int argc, char* argv[])
{
    int n=12, p=15;
    string str1= "monsieur", str2= "bonjour" ;

    cout << min(n,p) << endl;           
    cout << min(str1, str2) << endl;
}

На самом деле это говорит о том, что "min (n, p) неоднозначно и не знает, какую функцию вызывать. Возможно, это тривиальная проблема, но я не выяснил проблему. Я также попробовал следующие заголовки:

template<> string min(string str1, string str2)

и

template<> string min<string>(string str1, string str2)

Может ли кто-нибудь мне помочь?

Ответы [ 2 ]

2 голосов
/ 04 января 2012

Не шаблон, который не требует преобразования, всегда лучше подходит.То есть, если бы это были единственные определения min(), проблем не было бы (т. Е. Переименование функции min во что-то еще устранило бы неоднозначность).Неоднозначность находится между template <typename T> T const& std::min(T const&, T const&) и вашей шаблонной версией.Другое исправление заключается в удалении объявления using и явной квалификации имен из пространства имен std, то есть следующий код компилируется нормально:

#include <iostream>
#include <string>

template <class T> T min(T a, T b) { 
    return a < b? a: b;
}

std::string min(std::string str1, std::string str2) { 
    return str1.length() < str2.length()? str1: str2;
}    

int main()
{
    int n=12, p=15;
    std::string str1= "monsieur", str2= "bonjour" ;

    std::cout << min(n,p) << "\n";           
    std::cout << min(str1, str2) << "\n";
}

Обратите внимание, что версия std::string вашей min() равна не специализация, а перегрузка!При вызове функции, как вы сделали, это не имеет значения, и она выберет версию, как и ожидалось.Однако при вызове функции при явном указании аргумента шаблона она не будет:

min(str1, str2);              // calls string overload
min<std::string>(str1, str2); // calls the function template (*)

(*) На самом деле, min<std::string>(str1, str2), опять-таки, неоднозначна с версией из пространства имен std из-за зависимости аргументауважать;если бы он был назван по-другому, он вызвал бы версию шаблона.

Если вы хотите действительно специализировать функцию, вы бы написали что-то вроде этого:

template <> std::string min<std::string>(std::string, std::string) { ... }

Тем не менее, здесь есть несколько случайныхпримечания к программе, не связанные с неоднозначностью и специализацией:

  • В C ++ main() всегда должно быть объявлено для возврата intmain() разрешено пропускать оператор return, но некоторые компиляторы не получают этого права.Для переносимого кода лучше всего использовать возврат int и просто возвращать 0 (или EXIT_SUCCESS<code> declared in <code><stdlib.h>).
  • Вы почти наверняка захотите передать эти аргументы const ссылка: копированиеСтроки не такие дорогие, особенно для небольших std::string с (поскольку современные реализации std::string, похоже, используют оптимизацию небольших строк), но они также не бесплатны.Если объекты достаточно большие, это может привести к проблемам с производительностью.
  • Я предполагаю, что это всего лишь тест на перегрузку / специализацию.В противном случае, std::string версия min() не рекомендуется, поскольку она ведет себя непредвиденным образом.
  • ваши тестовые строки выбраны неправильно, поскольку они не показывают, что перегрузка / специализация действительно используется.
  • std::endl чрезмерно используется и делает что-то не так, как думает большинство людей: помимо вставки символа новой строки ('\ n'), он также сбрасывает std :: ostream .Это последняя часть, которая становится неожиданностью, и я обнаружил, что она создает серьезные проблемы с производительностью довольно часто.Если вы действительно не собираетесь очищать поток, просто напишите \ n .
2 голосов
/ 04 января 2012

Ваша проблема, вероятно, из-за противоречивых определений min где-то еще (возможно, в стандартной библиотеке).Попробуйте переименовать вашу функцию в my_min или как-нибудь еще.

Изменение имени функции сделало ваш пример корректным для меня.

...