сравнение строковых литералов в шаблонах c ++ - PullRequest
1 голос
/ 12 октября 2010

Я написал шаблонную функцию для сравнения двух переменных:

template <class t>

int compare(const t &a, const t &b) {

if(a>b) return 1;

if (a<b) return -1;

return 0;

}

int main(int argc, const char *argv[])
{

    cout << compare("hi","world");

    return 0;

}

Я получаю следующую ошибку

../src/templates.cpp: In function ‘int main(int, const char**)’:
../src/templates.cpp:11: error: no matching function for call to ‘compare(const char [3], const char [6])

Пожалуйста, объясните. Также, если я напишу cout << compare("hi", "wo");, он будет правильно скомпилирован. Или если я уберу & и объявлю функцию как int compare(const t a, const t b), она скомпилируется.

Ответы [ 6 ]

2 голосов
/ 12 октября 2010

Строковый литерал из N символов представляет собой массив из N константных символов с завершающим символом '\ 0' после этого. Таким образом, тип "hi" равен char const[3], а тип "world" равен char const[6].

Таким образом, если вы передадите его шаблону, t будет выведено для двух разных типов. Обратите внимание, что при использовании ссылочного параметра вычитание аргумента шаблона не преобразует массивы в указатели.

Также, пожалуйста, проверьте, сравнивая указатели друг с другом. То, как вы это сделаете, никогда не будет сравнивать строки лексически, а только их адреса, получая неопределенное значение. Вы можете исправить бит вывода аргумента, имея два отдельных параметра шаблона

template <class t, class u>
int compare(const t &a, const u &b) {
  if(a>b) return 1;
  if (a<b) return -1;

  return 0;
}

Clang выдает хорошее сообщение об ошибке

main1.cpp:17:5: error: no matching function for call to 'compare'
    compare("hi","world");
    ^~~~~~~
main1.cpp:4:5: note: candidate template ignored: 
  deduced conflicting types for parameter 't' ('char [3]' vs. 'char const[6]')
int compare(const t &a, const t &b) {
    ^
1 error generated.
1 голос
/ 12 октября 2010

В C ++, как и в C, строковые литералы являются символьными массивами с нулевым символом в конце. "hi" становится массивом символов ['h', 'i', 0]. C ++ рассматривает размер массива как часть его типа для шаблонов; строка "hi" - это массив длины 3, а строка "world" - это массив длины 6, поэтому компилятор не может найти один тип t, который соответствует обоим массивам.

Когда вы пытаетесь скомпилировать compare("hi", "wo"), компилятор обнаруживает, что тип t равен const char [3], поскольку обе строки - массивы - имеют одинаковую длину.

Когда вы отбрасываете &, массивы декодируются в константные указатели, поэтому компилятор находит, что тип t равен const char *. Обратите внимание, что в этом случае вы сравниваете указатели со строками, а не с их содержимым.

0 голосов
/ 07 июня 2016

Йоханнес Шауб - Литб показал вашу проблему.

И с этой проблемой, одним из лучших решений для этого случая является использование нетипизированных параметров шаблона .

template <signed N, signed M>
int compare(const char (&p1) [N], const char (&p2) [M] ){
    return strcmp(p1, p2);
}
0 голосов
/ 13 октября 2010

Если вам нужно , чтобы операторы сравнения работали в шаблоне для строк в стиле C (массивы с нулевым символом в конце char), вам потребуется специальный шаблон вместе с вашим общим шаблоном. Суть в том, что строки в стиле C нельзя сравнивать с помощью операторов.

template <class t>
int compare(const char * a, const char * b)
{
  return strcmp(a, b);
}

template <class t>
int compare(const t& a, const t& b)
{
  return (a == b) ? 0 : ((a < b) ? -1 : 1);
}

Примечание: эта шаблонная функция не будет работать для всех классов, которые не имеют operator<или operator== определено. , что приведет к хаосу в будущем.Это очень похоже на использование шаблонов C ++ для навязывания вещей в методологию языка C.

Лучший подход

Я вижу две специфические функции C ++, которые могут упростить вашу жизнь: перегрузка операторов и использованиеstd::string.Использование этих функций избавит вас от необходимости использовать шаблонные функции.

Операторы перегрузки

Одна из причин использования шаблонной функции сравнение состоит в том, что в классе нет операторов сравненияdevined ( в противном случае вы бы использовали операторы ).Итак, определите перегруженные операторы < и ==.Другие операторы >, >=, <= и != могут быть определены в терминах последних двух.См. boost header заголовка оператора.

Использование std::string

Проблема использования операторов сравнения в строках в стиле C может быть устранена путем замены их на std::string.Приятной особенностью std::string является то, что в нем уже определены операторы сравнения.Таким образом, вы можете использовать < для сравнения двух std::string объектов.

Сводка

Вместо создания шаблонной функции, которая использует сравнение в стиле C (например, return -1, 0 или +1), определите операторы сравнения для ваших классов и преобразуйте массивы символов с нулевым символом в конце в экземпляры std::string.

0 голосов
/ 12 октября 2010

Шаблонные функции преобразуются в реальную функцию с шаблонными классами, заменяемыми реальными классами компилятором. В вашем коде прототип вашей функции указывает, что

int compare(const t &a, const t &b)

оба a и b должны быть одного типа.

Когда вы вызываете compare("hi", "world");, для компилятора есть два разных типа для a и b, потому что "hi" имеет тип const char [3], а "world" имеет тип const char [6]. Компилятор не может реализовать хорошую версию compare().

Но когда вы звоните compare("hi", "wo");, вдруг оба становятся одного типа: const char [3], и нет никакой двусмысленности.

Если вы реализуете функцию как int compare(const t a, const t b), компилятор найдет альтернативу для t: char *. Массивы будут преобразованы в const char *, поэтому двусмысленности нет.

0 голосов
/ 12 октября 2010

Тип строкового литерала "hi" - const char [3].Тип строкового литерала "мир" - const char [6].Так что это разные типы.

Ваш шаблон сравнения использует один и тот же тип для обоих параметров, поэтому он не будет работать.

Измените шаблон сравнения, чтобы использовать разные типы для двух параметров.Также вам нужно будет предоставить перегрузку для правильного сравнения строковых литералов.

Если вы просто напишите (a>b), массивы a и b распадутся на указатели, так что вы на самом деле будете сравнивать только адресапервые символы строковых литералов.

...