Логическая ошибка в шаблоне функции - PullRequest
4 голосов
/ 12 октября 2010

Мой профессор дал мне это назначение.

Реализуйте универсальную функцию с именем Max, которая принимает 3 аргумента универсального типа и возвращает максимум из них 3. Реализует специализированную функцию для типов char *.

Вот мой код:

#include <iostream>
#include <string>

using namespace std;

template<typename T>
T Max(T first,T second,T third )
{
    if(first > second)
    {
        if(first > third)
        {
            return first;
        }
        else
        {
            return third;
        }
    }
    else if(second > third)
    {
        return second;
    }
    else
    {
        return third;
    }
}


template<>
char* Max(char* first,char* second,char* third)
{   
    if(strcmp(first, second) > 0)
    {
        if(strcmp(first, third) > 0)
        {
            return first;
        }
        else
        {
            return third;
        }
    }
    else if(strcmp(second, third) > 0)
    {
        return second;
    }
    else
    {
        return third;
    }
}

int main(void)
{
    cout << "Greatest in 10, 20, 30 is " << Max(10, 20, 30) << endl;

    char a = 'A';
    char b = 'B';
    char c = 'C';
    char Cptr = *Max(&a, &b, &c);
    cout << "Greatest in A, B ,C is " << Cptr << endl;

    string d = "A";
    string e = "B";
    string f = "C";
    string result = *Max(&d, &e, &f);

    cout << "Greatest in A, B, C is " << result << endl;
}

Вывод:

Максимум в 10,20, 30 - 30
Наибольшее значение для A, B, C - это C
Наибольшее значение для A, B, C - это

Проблема:

Если я передаю типы данных char в функции Max A, B, C, он возвращает C, но если я передаю строковые типы данных A, B, C, он возвращает A.

Почему он возвращает A здесь?

Ответы [ 4 ]

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

Здесь есть две проблемы.В двух других ответах уже описана проблема с вашим третьим вызовом.

Но ваш второй вызов также неверен:

char a = 'A';
char b = 'B';
char c = 'C';
char Cptr = *Max(&a, &b, &c);

Это должно привести к неопределенному поведению, поскольку strcmp ожидает завершения с нуля.строки, но это не то, что вы вводите в функцию.Скорее, вы передаете указатели на отдельные значения char, и strcmp имеет полное право подавить это.В принципе, может случиться что угодно, и что ваш код работает, это просто случайность.

Правильный способ вызвать эту перегрузку - просто передать char s или передать строки в стиле C:

char C = Max(a, b, c);

// or:
char as[] = "a";
char bs[] = "b";
char cd[] = "c";
char* result = Max(as, bs, cd);

Кроме того, вы можете передать строковые литералы напрямую.

Наконец, заметка о стиле.Ваша char* специализация может быть значительно сокращена, если вы немного «обманываете» путем преобразования входящих char* строк в правильные std::string s и повторного использования универсальной версии Max:

template<>
char* Max(char* first,char* second,char* third)
{
    return Max(string(first), string(second), string(third));
}

(Конечно, это, вероятно, менее эффективно, но в большинстве случаев это может быть безопасно проигнорировано.)

И еще одно замечание: назначение явно просило вас специализировать шаблон функции для char*, поэтому ваш ответправильный.Однако альтернативой может быть перегрузка функции вместо ее специализации.Для шаблонов функций (в отличие от шаблонов классов) это обычный способ, когда вам не требуется больше аргументов шаблона:

char* Max(char* first,char* second,char* third)
{
    return Max(string(first), string(second), string(third));
}

Обратите внимание, что единственное отличие заключается в отсутствии template <> передзаголовок функции.

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

В первом случае используется специализация шаблона, во втором - общий шаблон.

Но ваша проблема в том, как вы звоните Max во втором случае:

string d = "A";
string e = "B";
string f = "C";
// you're comparing the string addresses here, not their content
string result = *Max(&d, &e, &f); 

Должно быть:

string d = "A";
string e = "B";
string f = "C";
string result = Max(d, e, f);

Кроме того, я бы предложил использовать указатели const в специализации char*, поскольку в нынешнем виде вы не можете передавать ничего, кроме неконстантных указателей, что не совсем обычный случай.

2 голосов
/ 12 октября 2010
string result = *Max(&d, &e, &f);

Эта строка - ваша проблема.Вы передаете указатель на строку, так что он на самом деле возвращает самый высокий адрес указателя.

Имейте в виду, что стек растет вниз, поэтому у начала стека самый высокий адрес.Каждое последующее выделение стека (т. Е. Объявление переменной в этом случае) будет начинаться с постепенно уменьшающегося адреса стека, и, следовательно, «A» отображается как наибольшее значение.

Если вы напишите это:

string result = Max(d, e, f);

Вы получите ожидаемый ответ.

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

вместо

string result = *Max(*&d, &e, &f)

вам нужно

string result = Max(d.c_str(), e.c_str(), f.c_str())

Обратите внимание, что это будет работать, если ваша функция принимает const char*, а не char*.Если вы настаиваете на использовании char *, что неправильно, вам придется отбросить константу

 string result = Max(const_cast<char*>(d.c_str()),

 const_cast<char*>(e.c_str()), const_cast<char*>(f.c_str()));

, но, поскольку вы используете string s, обратите внимание, что вы можете сравнить их просто с ==<> и т. д.

...