English 中文(简体)
比较c++模板中的字符串文字
原标题:comparing string literals in c++ templates

我编写了一个模板函数来比较两个变量:

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])

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.

最佳回答

说明N级特性的字面是一系列N级常态,随后将断。 因此,<代码>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.
问题回答

在C++中,与在C中一样,字符串文字是以nul结尾的字符数组“hi”变为字符数组[h,i,0]。C++将数组的大小视为模板类型的一部分;字符串“hi”是长度为3的数组,字符串world为长度为6的数组,因此编译器无法找到与两个数组匹配的单一类型t

当您试图编译compare(“hi”,“wo”)时,编译器会发现t类型是const-char[3],因为两个字符串(数组)的长度相同。

当你放下&,数组解码为const指针,因此编译器发现t类型为const-char*。请注意,在这种情况下,您将指针与字符串进行比较,而不是将其内容进行比较。

约翰内斯·绍布·利特布展示了你的问题。

对于这个问题,这种情况的最佳解决方案之一是使用非类型模板参数

template <signed N, signed M>
int compare(const char (&p1) [N], const char (&p2) [M] ){
    return strcmp(p1, p2);
}

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.

您的比较模板对两个参数使用相同的类型,因此这不会成功。

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.

如果你只写(a>;b),数组a和b将衰减为指针,所以你实际上只比较字符串文字的第一个字符的地址。

模板函数被转换为实函数,编译器用实类替换模板类。在您的代码中,您的函数原型表明,

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

ab必须是相同的类型。

当您调用<code>compare(“hi”,“world”)时a和b有两种不同的类型,因为“hi”是const-char[3]类型,而“world”是const-char[6]的类型。编译器无法实现compare()的良好版本。

但当您调用<code>compare(“hi”,“wo”)时,突然两者变成了同一类型:constchar[3]并且没有歧义。

如果将函数实现为int compare(const t a,const t b),编译器会为t:char*找到一个替代方案。数组将被转换为const-char*,因此不存在歧义。

如果需要让比较运算符在C样式字符串的模板(char的null终止数组)中工作,则必须在通用模板的同时提供一个专用模板问题在于无法使用运算符对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);
}

注意:对于所有没有运算符<运算符==这将在今后造成严重破坏。这看起来很像是使用C++模板将事情强制到C语言方法论中。

A Better Approach

我看到了两个特定于C++的特性,它们可以让您的生活更轻松:重载运算符和使用std::string。使用这些功能将消除对模板化函数的需求。

Overloading Operators

使用模板化compare函数的一个原因是,该类没有指定比较运算符(否则将使用运算符)。因此,定义重载运算符<==。其他运算符>>;=时<==可以用后两者来定义。请参阅boost运算符标题。

Using std::string

在C样式字符串上使用比较运算符的问题可以通过将它们替换为std::string来解决。<code>std::string</code>的一个好特性是它已经定义了比较运算符。因此,您可以使用<来比较两个std::string对象。

Summary

与其创建使用C样式比较的模板函数(例如return-1、0或+1),不如为类定义比较运算符,并将以null结尾的字符数组转换为std::string的实例。





相关问题
Simple JAVA: Password Verifier problem

I have a simple problem that says: A password for xyz corporation is supposed to be 6 characters long and made up of a combination of letters and digits. Write a program fragment to read in a string ...

Case insensitive comparison of strings in shell script

The == operator is used to compare two strings in shell script. However, I want to compare two strings ignoring case, how can it be done? Is there any standard command for this?

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

String initialization with pair of iterators

I m trying to initialize string with iterators and something like this works: ifstream fin("tmp.txt"); istream_iterator<char> in_i(fin), eos; //here eos is 1 over the end string s(in_i, ...

break a string in parts

I have a string "pc1|pc2|pc3|" I want to get each word on different line like: pc1 pc2 pc3 I need to do this in C#... any suggestions??

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...