比较 c++ 中的字符串文字模板
我编写了一个模板函数来比较两个变量:
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 ta, const tb)
的函数,它会编译。
I wrote a template function to compare two variables:
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;
}
I get the following error
../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])
Please explain.
Also if I write cout << compare("hi", "wo");
it compiles properly.
Or if I remove the &
and declare the function like int compare(const t a, const t b)
it compiles.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
N 个字符的字符串文字是一个由 N 个常量字符组成的数组,后面带有终止符 '\0'。所以
"hi"
的类型是char const[3]
,"world"
的类型是char const[6]< /代码>。
因此,如果将其传递给模板,
t
就会被推导为两种不同的类型。请注意,在引用参数中时,模板参数推导不会将数组转换为指针。另外,请检查相互比较指针。您这样做的方式不会在词法上比较字符串,而只会比较它们的地址,从而产生未指定的值。您可以通过使用两个单独的模板参数来修复参数推导位
Clang 给出了很好的错误消息
A string literal of N characters is an array of N constant characters with a terminating '\0' afterwards. So type of
"hi"
ischar const[3]
and the one of"world"
ischar const[6]
.So if you pass it to the template,
t
is deduced to two different types. Note that when in a reference parameter, template argument deduction does not transform arrays to pointers.Also, please check up in comparing pointers to each other. The way you do that won't ever compare the strings lexically, but just the addresses of them, yielding an unspecified value. You can fix the argument deduction bit by having two separate template parameters
Clang gives a good error message
在 C++ 中,与 C 中一样,字符串文字是以 null 结尾的字符数组。
"hi"
变为字符数组['h', 'i', 0]
。 C++ 将数组的大小视为模板类型的一部分;字符串"hi"
是一个长度为3的数组,而字符串"world"
是一个长度为6的数组,因此编译器无法找到单个类型< code>t 匹配两个数组。当您尝试编译
compare("hi", "wo")
时,编译器会发现类型t
是const char [3]
,因为两个字符串(数组)具有相同的长度。当您删除
&
时,数组将解码为 const 指针,因此编译器会发现类型t
是const char *
。请注意,在这种情况下,您将指针与字符串进行比较,而不是它们的内容。In C++, as in C, string literals are nul-terminated character arrays.
"hi"
becomes the character array['h', 'i', 0]
. C++ treats the size of the array as part of its type for templates; the string"hi"
is an array of length 3, and the string"world"
is an array of length 6, so the compiler can't find a single typet
that matches both arrays.When you try to compile
compare("hi", "wo")
the compiler finds that typet
isconst char [3]
, since both strings -- arrays -- have the same length.When you drop the
&
, the arrays decode into const pointers, so the compiler finds that typet
isconst char *
. Note that in this case, you're comparing the pointers to the strings, not their contents.Johannes Schaub - litb 显示了你的问题。
对于这个问题,这种情况的最佳解决方案之一是使用非类型模板参数。
Johannes Schaub - litb showed your problem.
And with that problem, one of the best solution for this case is using Nontype Template Parameters.
字符串文字“hi”的类型是const char [3]。
字符串文字“world”的类型是const char [6] 。
所以他们是不同的类型。
您的比较模板对两个参数使用相同的类型,因此这不会成功。
更改比较模板以对两个参数使用不同的类型。
此外,您还必须提供重载才能正确比较字符串文字。
如果您只编写
(a>b)
,数组 a 和 b 将衰减为指针,因此您实际上只是比较字符串文字的第一个字符的地址。The type of the string literal "hi" is
const char [3]
.The type of the string literal "world" is
const char [6]
.So they're different types.
Your compare template uses the same type for both parameters, so this won't fly.
Change your compare template to use different types for the two parameters.
Also you will have to provide an overload to compare string literals correctly.
If you just write
(a>b)
, the arrays a and b will decay into pointers, so you'd be really only comparing the addresses of the first characters of the string literals.模板函数转换为真实函数,编译器将模板类替换为真实类。在您的代码中,您的函数原型表明
a
和b
必须属于相同类型。当您调用
compare("hi", "world");
时,对于编译器来说,有两种不同的类型a
和b
因为“hi " 的类型为const char [3]
类型,“world” 的类型为const char [6]
。编译器无法实现良好版本的compare()
。但是当你调用compare("hi", "wo");时,突然两者都变成相同的类型:
const char [3]
并且没有歧义。如果将该函数实现为 intcompare(const ta, const tb),编译器会找到 t 的替代方案:char *。数组将被转换为 const char * ,因此不会有歧义。
Template functions are converted into real function with template classes replaced with real classes by the compiler. In your code, your function prototype indicates that,
both
a
andb
must be of same type.When you call
compare("hi", "world");
, for compiler there are two different types fora
andb
because "hi" is of typeconst char [3]
and "world" is of typeconst char [6]
. The compiler cannot implement a good version ofcompare()
.But when you call
compare("hi", "wo");
, suddenly both becomes of same type:const char [3]
and there is no ambiguity.If you implement the function as
int compare(const t a, const t b)
the compiler finds an alternative for t:char *
. The arrays will be converted intoconst char *
and thus there is no ambiguity.如果您需要让比较运算符在 C 样式字符串(
char
的 null 终止数组)的模板中工作,则必须有一个专门的模板以及您的模板。通用模板。 棘手的是 C 风格的字符串无法使用运算符进行比较。注意:对于所有没有
operator<
或的类,此模板化函数将会失败。 code>operator==
已定义。 这会造成严重破坏。这看起来非常像使用 C++ 模板将事物强制转换为 C 语言方法。更好的方法
我看到两个 C++ 特定功能可以让您的生活更轻松:重载运算符和使用
std::string
。使用这些功能将消除您对模板化函数的需求。重载运算符
使用模板化compare函数的原因之一是该类没有定义比较运算符(否则您将使用这些运算符)。因此,定义重载运算符
<
和==
。其他运算符>、>=、<=
和!=
可以根据后两者来定义。请参阅boost
运算符标头。使用
std::string
在 C 风格字符串上使用比较运算符的问题可以通过将其替换为
std::string
来解决。std::string
的一个很好的功能是它已经定义了比较运算符。因此,您可以使用<
来比较两个std::string
对象。总结
不要创建使用 C 风格比较(例如返回 -1、0 或 +1)的模板函数,而是为您的类定义比较运算符并将以 null 结尾的字符数组转换为
std::string< 的实例/代码>。
If you need to have the comparison operators work in a template for C-style strings (null terminated arrays of
char
), you will have to have a specialized template along with your generic template. The thorn is that C-style strings cannot be compared using the operators.Note: This templated function will fail for all classes that do not have
operator<
oroperator==
defined. Which will cause havoc down the road. This looks very much like a using C++ templates to force things into the C language methodology.A Better Approach
I see two C++ specific features that could make your life easier: Overloading operators and using
std::string
. Using these features will eliminate your need for the templated functions.Overloading Operators
One reason for having a templated compare function is because the class doesn't have comparison operators devined (otherwise you would use the operators). So, define the overloaded operators
<
and==
. The other operators>, >=, <=
and!=
can be defined in terms of the latter two. Seeboost
operators header.Using
std::string
The problem of using comparison operators on C-style strings can be removed by replacing them with
std::string
. A nice feature ofstd::string
is that it has the comparison operators already defined. Thus you can use<
to compare twostd::string
objects.Summary
Rather than creating a template function that uses C-style comparing (e.g. return -1, 0, or +1), define comparison operators for your classes and convert null terminated arrays of characters into instances of
std::string
.