我写了一个模板函数来比较两个变量:
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)
这样的函数,则会编译。
答案 0 :(得分:2)
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 :(得分:1)
在C ++中,与C一样,字符串文字是以空字符结尾的字符数组。 "hi"
成为字符数组['h', 'i', 0]
。 C ++将数组的大小视为模板类型的一部分;字符串"hi"
是一个长度为3的数组,字符串"world"
是一个长度为6的数组,因此编译器找不到与两个数组匹配的单个类型t
。 / p>
当您尝试编译compare("hi", "wo")
时,编译器发现类型t
为const char [3]
,因为两个字符串 - 数组 - 具有相同的长度。
当您删除&
时,数组会解码为const指针,因此编译器会发现类型t
为const char *
。请注意,在这种情况下,您将指针与字符串进行比较,而不是将其内容进行比较。
答案 2 :(得分:0)
字符串文字“hi”的类型是const char [3]
。
字符串文字“world”的类型是const char [6]
。
所以他们的类型不同。
您的比较模板对两个参数使用相同的类型,因此不会飞。
更改比较模板,为两个参数使用不同的类型。 此外,您必须提供重载以正确比较字符串文字。
如果你只是写(a>b)
,数组a和b将衰减为指针,所以你真的只是比较字符串文字的第一个字符的地址。
答案 3 :(得分:0)
模板函数转换到实际函数中,编译器将模板类替换为实际类。在您的代码中,您的函数原型指示
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 *
,因此没有歧义。
答案 4 :(得分:0)
如果你需要让比较运算符在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
。使用这些功能将消除您对模板化功能的需求。
使用模板化 compare 函数的一个原因是因为类没有设置比较运算符(否则您将使用运算符)。因此,请定义重载的运算符<
和==
。其他运算符>, >=, <=
和!=
可以根据后两者来定义。请参阅boost
运营商标题。
std::string
可以通过用std::string
替换它们来消除在C风格字符串上使用比较运算符的问题。 std::string
的一个很好的特性是它已经定义了比较运算符。因此,您可以使用<
来比较两个std::string
个对象。
不是创建使用C样式比较的模板函数(例如返回-1,0或+1),而是为类定义比较运算符,并将空终止的字符数组转换为std::string
的实例。
答案 5 :(得分:0)
Johannes Schaub - litb显示了你的问题。
对于这个问题,本案例的最佳解决方案之一是使用非类型模板参数。
template <signed N, signed M>
int compare(const char (&p1) [N], const char (&p2) [M] ){
return strcmp(p1, p2);
}