功能模板中的逻辑错误

时间:2010-10-12 08:36:11

标签: c++ stl function-templates

我的教授给了我这个任务。

  

实现一个名为的泛型函数   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是   甲

问题:

如果我在Max函数A,B,C中传递char数据类型,它将返回C,但如果我传递字符串数据类型A,B,C,则返回A.

为什么在这里返回A?

4 个答案:

答案 0 :(得分:4)

这里有两个问题。其他两个答案已经描述了第三次电话会议的问题。

但你的第二次电话也错了:

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

这会产生未定义的行为,因为strcmp期望以零结尾的字符串,但这不是您输入函数的内容。相反,您将指针传递给单个char值,而strcmp则有权对此进行扼杀。基本上,任何事情都可能发生,而且你的代码工作是纯粹的机会。

调用此重载的正确方法是传递char或传递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的通用版本来“欺骗”一点,那么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 <>

答案 1 :(得分:2)

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

此行是您的问题。您正在将指针传递给字符串,因此它实际上返回了最高的指针地址。

请记住堆栈向下增长,因此堆栈的开头具有最高地址。每个后续堆栈分配(即本例中的变量声明)将开始逐渐降低堆栈地址,因此“A”显示为最大值。

如果你这样写:

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

你会得到你期望的答案。

答案 2 :(得分:2)

在第一种情况下,它使用模板专门化,在第二种情况下,使用通用模板。

但问题是你在第二种情况下调用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*指针,因为就目前而言,除了非常量指针之外,你不能传递任何东西,这不是常见的情况。

答案 3 :(得分:1)

而不是

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

你需要

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

请注意,如果您的功能需要const char*而非char*,则此功能将起作用。如果你坚持使用char *,这是错误的,那么你将不得不抛弃constness

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

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

但由于您使用的是string,请注意您只需将它们与==&lt;进行比较即可。 &GT;等