C++ Primer Fourth Edition 16.7 的疑问!

mymtom 2013-01-18 10:47:19
不知道是不是错误,请高手帮忙看看
红色的部分说:
模板函数和普通函数都匹配,但事实上,当我把这个函数
int compare(const char*, const char*);

注释掉之后,会报错的:

no matching function for call to 'compare(const char [6], const char [3])'
no matching function for call to 'compare(char [6], char [3])'

那就是说模板函数根本就不匹配啊!

16.7. Overloading and Function Templates
An Example of Function-Template Matching
Consider the following set of overloaded ordinary and function templates:

// compares two objects
template <typename T> int compare(const T&, const T&);
// compares elements in two sequences
template <class U, class V> int compare(U, U, V);
// plain functions to handle C-style character strings
int compare(const char*, const char*);

The overload set contains three functions: The first template handles simple values, the second template compares elements from two sequences, and the third is an ordinary function to handle C-style character strings.

Resolving Calls to Overloaded Function Templates
We could call these functions on a variety of types:

// calls compare(const T&, const T&) with T bound to int
compare(1, 0);
// calls compare(U, U, V), with U and V bound to vector<int>::iterator
vector<int> ivec1(10), ivec2(20);
compare(ivec1.begin(), ivec1.end(), ivec2.begin());
int ia1[] = {0,1,2,3,4,5,6,7,8,9};
// calls compare(U, U, V) with U bound to int*
// and V bound to vector<int>::iterator
compare(ia1, ia1 + 10, ivec1.begin());
// calls the ordinary function taking const char* parameters
const char const_arr1[] = "world", const_arr2[] = "hi";
compare(const_arr1, const_arr2);
// calls the ordinary function taking const char* parameters
char ch_arr1[] = "world", ch_arr2[] = "hi";
compare(ch_arr1, ch_arr2);


We'll look at each call in turn:

compare(1, 0): Both arguments have type int. The candidate functions are the first template instantiated with T bound to int and the ordinary function named compare. The ordinary function, however, isn't viablewe cannot pass an int to a parameter expecting a char*. The instantiated function using int is an exact match for the call, so it is selected.

compare(ivec1.begin(), ivec1.end(), ivec2.begin())

compare(ia1, ia1 + 10, ivec1.begin()): In these calls, the only viable function is the instantiation of the template that has three parameters. Neither the template with two arguments nor the ordinary nonoverloaded function can match these calls.

compare(const_arr1, const_arr2): This call, as expected, calls the ordinary function. Both that function and the first template with T bound to const char* are viable. Both are also exact matches. By rule 3b, we know that the ordinary function is preferred. We eliminate the instance of the template from consideration, leaving just the ordinary function as viable.

compare(ch_arr1, ch_arr2): This call also is bound to the ordinary function. The candidates are the version of the function template with T bound to char* and the ordinary function that takes const char* arguments. Both functions require a trivial conversion to convert the arrays, ch_arr1 and ch_arr2, to pointers. Because both functions are equal matches, the plain function is preferred to the template version.

...全文
1299 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
lvjing_CSDN 2013-11-20
  • 打赏
  • 举报
回复
引用 14 楼 iforget33 的回复:
[quote=引用 7 楼 lvjing_CSDN 的回复:] 我觉得书上错了,template <typename T> int compare(const T&, const T&);的模板行惨是引用类型,如果传递的是数组的话,compare的两个行参都是引用类型,要求两个数组的维度都相同,但是树上给的两个数组的维度不一样,无法用来实例化。不过把这个函数的行惨定义位非引用类型就可以了,或者把那两个数组的维度改成相同的。
如果改成char ch_arr1[6]="world",ch_arr2[6]="hihih"; 维数相同了,T绑定到char (&)[6],而非模版函数还用从char*转换到const char *, 但为什么还是调用非模版函数呢?[/quote] 这个是因为编译器认为模板实例化的版本和非模板版本是同样好的(即这个调用是有二义性的),编译器就把模板版本去掉了。至于为什么编译器认为这两个版本是同样好的,我觉得是因为虽然有数组到指针的转换,但是编译器无法区别“传递副本和引用哪个更好”(非重载版本传递指针的副本,重载版本传递引用),你可以试试如下的重载
void print(int *arr);
void print(int (&arr)[10]);
int arr[10];
print(arr);//ambiguous
另,这个只是我个人的理解,我对上述的解释并没有十足的把握,仅供参考。
iforget33 2013-11-15
  • 打赏
  • 举报
回复
引用 7 楼 lvjing_CSDN 的回复:
我觉得书上错了,template <typename T> int compare(const T&, const T&);的模板行惨是引用类型,如果传递的是数组的话,compare的两个行参都是引用类型,要求两个数组的维度都相同,但是树上给的两个数组的维度不一样,无法用来实例化。不过把这个函数的行惨定义位非引用类型就可以了,或者把那两个数组的维度改成相同的。
如果改成char ch_arr1[6]="world",ch_arr2[6]="hihih"; 维数相同了,T绑定到char (&)[6],而非模版函数还用从char*转换到const char *, 但为什么还是调用非模版函数呢?
zhangnantzp 2013-01-18
  • 打赏
  • 举报
回复
引用 7 楼 lvjing_CSDN 的回复:
我觉得书上错了,template <typename T> int compare(const T&, const T&);的模板行惨是引用类型,如果传递的是数组的话,compare的两个行参都是引用类型,要求两个数组的维度都相同,但是树上给的两个数组的维度不一样,无法用来实例化。不过把这个函数的行惨定义位非引用类型就可以了,或者把那两个数组的维度改成相同……
大神,帮我看看这个问题呗。。。http://bbs.csdn.net/topics/390350326
zhangnantzp 2013-01-18
  • 打赏
  • 举报
回复
引用 7 楼 lvjing_CSDN 的回复:
我觉得书上错了,template <typename T> int compare(const T&, const T&);的模板行惨是引用类型,如果传递的是数组的话,compare的两个行参都是引用类型,要求两个数组的维度都相同,但是树上给的两个数组的维度不一样,无法用来实例化。不过把这个函数的行惨定义位非引用类型就可以了,或者把那两个数组的维度改成相同……
你说的太对了,我本来也疑惑呢,我忘了如果形参是引用类型的话,不会将数组名转化为指针,而是直接传递数组的引用本身
lvjing_CSDN 2013-01-18
  • 打赏
  • 举报
回复
我觉得书上错了,template <typename T> int compare(const T&, const T&);的模板行惨是引用类型,如果传递的是数组的话,compare的两个行参都是引用类型,要求两个数组的维度都相同,但是树上给的两个数组的维度不一样,无法用来实例化。不过把这个函数的行惨定义位非引用类型就可以了,或者把那两个数组的维度改成相同的。
ri_aje 2013-01-18
  • 打赏
  • 举报
回复
编译器是正确的,第一个函数模板匹配不上,除非改成这样。

template <typename T, typename U> int compare(const T&, const U&);
  • 打赏
  • 举报
回复
首先肯定不会匹配3个参数的compare 然后你传递是const_arr1,那么模板推导出来的参数类型就是数组的引用 参数分别是 const char &[6] , const char &[3]这是2个不同的类型 int compare(const T&, const T&);要求两个参数都一致,所以无法匹配了。
compare((const char*)const_arr1, (const char*)const_arr2);
这样就能匹配上模板参数
lee_鹿游原 2013-01-18
  • 打赏
  • 举报
回复

16.7. Overloading and Function Templates
16.7. 重载与函数模板
A function template can be overloaded: We can define multiple function templates with the same name but differing numbers or types of parameters. We also can define ordinary nontemplate functions with the same name as a function template.

函数模板可以重载:可以定义有相同名字但形参数目或类型不同的多个函数模板,也可以定义与函数模板有相同名字的普通非模板函数。

Of course, declaring a set of overloaded function templates does not guarantee that they can be called successfully. Overloaded function templates may lead to ambiguities.

当然,声明一组重载函数模板不保证可以成功调用它们,重载的函数模板可能会导致二义性。

Function Matching and Function Templates
函数匹配与函数模板
The steps used to resolve a call to an overloaded function in which there are both ordinary functions and function templates are as follows:

如果重载函数中既有普通函数又有函数模板,确定函数调用的步骤如下:

1.  Build the set of candidate functions for this function name, including:
为这个函数名建立候选函数集合,包括:


Any ordinary function with the same name as the called function.

与被调用函数名字相同的任意普通函数。

Any function-template instantiation for which template argument deduction finds template arguments that match the function arguments used in the call.

任意函数模板实例化,在其中,模板实参推断发现了与调用中所用函数实参相匹配的模板实参。
 
2.  Determine which, if any, of the ordinary functions are viable (Section 7.8.2, p. 269). Each template instance in the candidate set is viable, because template argument deduction ensures that the function could be called.
确定哪些普通函数是可行的(第 7.8.2 节)(如果有可行函数的话)。候选集合中的每个模板实例都 可行的,因为模板实参推断保证函数可以被调用。
 
3.  Rank the viable functions by the kinds of conversions, if any, required to make the call, remembering that the conversions allowed to call an instance of a template function are limited.
如果需要转换来进行调用,根据转换的种类排列可靠函数,记住,调用模板函数实例所允许的转换是有限的。

If only one function is selected, call this function.

如果只有一个函数可选,就调用这个函数。

If the call is ambiguous, remove any function template instances from the set of viable functions.

如果调用有二义性,从可行函数集合中去掉所有函数模板实例。
 
4.  Rerank the viable functions excluding the function template instantiations.
重新排列去掉函数模板实例的可行函数。

If only one function is selected, call this function.

如果只有一个函数可选,就调用这个函数。

Otherwise, the call is ambiguous.

否则,调用有二义性。
 

An Example of Function-Template Matching
函数模板匹配的例子
Consider the following set of overloaded ordinary and function templates:

考虑下面普通函数和函数模板的重载集合:

     // compares two objects
     template <typename T> int compare(const T&, const T&);
     // compares elements in two sequences
     template <class U, class V> int compare(U, U, V);
     // plain functions to handle C-style character strings
     int compare(const char*, const char*);



The overload set contains three functions: The first template handles simple values, the second template compares elements from two sequences, and the third is an ordinary function to handle C-style character strings.

重载集合包含三个函数:第一个模板处理简单值,第二个模板比较两个序列的元素,第三个是处理 C 风格字符串的普通函数。

Resolving Calls to Overloaded Function Templates
确定重载函数模板的调用
We could call these functions on a variety of types:

可以在不同类型上调用这些函数:

     // calls compare(const T&, const T&) with T bound to int
     compare(1, 0);
     // calls compare(U, U, V), with U and V bound to vector<int>::iterator
     vector<int> ivec1(10), ivec2(20);
     compare(ivec1.begin(), ivec1.end(), ivec2.begin());
     int ia1[] = {0,1,2,3,4,5,6,7,8,9};
     // calls compare(U, U, V) with U bound to int*
     // and V bound to vector<int>::iterator
     compare(ia1, ia1 + 10, ivec1.begin());
     // calls the ordinary function taking const char* parameters
     const char const_arr1[] = "world", const_arr2[] = "hi";
     compare(const_arr1, const_arr2);
     // calls the ordinary function taking const char* parameters
     char ch_arr1[] = "world", ch_arr2[] = "hi";
     compare(ch_arr1, ch_arr2);



We'll look at each call in turn:

下面依次介绍每个调用。

compare(1, 0): Both arguments have type int. The candidate functions are the first template instantiated with T bound to int and the ordinary function named compare. The ordinary function, however, isn't viablewe cannot pass an int to a parameter expecting a char*. The instantiated function using int is an exact match for the call, so it is selected.

两个形参都是 int 类型。候选函数是第一个模板将 T 绑定到 int 的实例化,以及名为 compare 的普通函数。但该普通函数不可行——不能将 int 对象传给期待 char* 对象的形参。用 int 实例化的函数与该调用完全匹配,所以选择它。

     compare(ivec1.begin(), ivec1.end(), ivec2.begin())



compare(ia1, ia1 + 10, ivec1.begin()): In these calls, the only viable function is the instantiation of the template that has three parameters. Neither the template with two arguments nor the ordinary nonoverloaded function can match these calls.

这两个调用中,唯一可行的函数是有三个形参的模板的实例化。带两个参数的模板和普通非模板函数都不能匹配这两个调用。

compare(const_arr1, const_arr2): This call, as expected, calls the ordinary function. Both that function and the first template with T bound to const char* are viable. Both are also exact matches. By rule 3b, we know that the ordinary function is preferred. We eliminate the instance of the template from consideration, leaving just the ordinary function as viable.

这个调用正如我们所期待的,调用普通函数。该函数和将 T 绑定到 const char* 的第一个模板都是可行的,也都完全匹配。根据规则 3b,会选择普通函数。从候选集合中去掉模板实例,只剩下普通函数可行。

compare(ch_arr1, ch_arr2): This call also is bound to the ordinary function. The candidates are the version of the function template with T bound to char* and the ordinary function that takes const char* arguments. Both functions require a trivial conversion to convert the arrays, ch_arr1 and ch_arr2, to pointers. Because both functions are equal matches, the plain function is preferred to the template version.

这个调用也绑定到普通函数。候选者是将 T 绑定到 char* 的函数模板的版本,以及接受 const char* 实参的普通函数,两个函数都需要稍加转换将数组 ch_arr1 和 ch_arr2 转换为指针。因为两个函数一样匹配,所以普通函数优先于模板版本。

Conversions and Overloaded Function Templates
转换与重载的函数模板
It can be difficult to design a set of overloaded functions in which some are templates and others are ordinary functions. Doing so requires deep understanding of the relationships among types and in particular of the implicit conversions that may or may not take place when templates are involved.

设计一组重载函数,其中一些是模板而另一些是普通函数,这可能是困难的。这样做需要深入理解类型之间的关系,具体而言,就是当涉及模板时可以发生和不能发生的隐式转换。

Let's look at two examples of why it is hard to design overloaded functions that work properly when there are both template and nontemplate versions in the overload set. First, consider a call to compare using pointers instead of the arrays themselves:

来看两个例子,看看为什么当重载集合中既有模板又有非模板版本的时候,设计正确工作的重载函数是困难的。首先,考虑用指针代替数组本身的 compare 调用:

     char *p1 = ch_arr1, *p2 = ch_arr2;
     compare(p1, p2);



This call matches the template version! Ordinarily, we expect to get the same function whether we pass an array or a pointer to an element to that array. In this case, however, the function template is an exact match for the call, binding char* to T. The plain version still requires a conversion from char* to const char*, so the function template is preferred.

这个调用与模板版本匹配!通常,我们希望无论是传递数组,还是传递指向该数组元素的指针,都获得同一函数。但是,在这个例子中,将 char* 绑定到 T 的函数模板与该调用完全匹配。普通版本仍然需要从 char* 到 const char* 的转换,所以优先选择函数模板。

Another change that has surprising results is what happens if the template version of compare has a parameter of type T instead of a const reference to T:

另一个具有惊人结果的改变是,如果 compare 的模板版本有一个 T 类型的形参代替 T 的 const 引用,会发生的情况:

     template <typename T> int compare2(T, T);



In this case, if we have an array of plain char; then, whether we pass the array itself or a pointer, the template version is called. The only way to call the nontemplate version is when the arguments are arrays of const char or pointers to const char*:

这个例子中,如果有一个普通类型的数组,则无论传递数组本身,还是传递指针,都将调用模板版本。调用非模板版本的唯一途径是在实参是 const char 或者 const char* 指针数组的时候:

     // calls compare(T, T) with T bound to char*
     compare(ch_arr1, ch_arr2);
     // calls compare(T, T) with T bound to char*
     compare(p1, p2);
     // calls the ordinary function taking const char*
     parameters compare(const_arr1, const_arr2);
     const char *cp1 = const_arr1, *cp2 = const_arr2;
     // calls the ordinary function taking const char* parameters
     compare(cp1, cp2);



In these cases, the plain function and the function template are exact matches. As always, when the match is equally good, the nonoverloaded version is preferred.

在这些情况下,普通函数和函数模板都完全匹配。像通常一样,当匹配同样好时,非模板版本优先。

 It is hard to design overloaded function sets involving both function templates and nontemplate functions. Because of the likelihood of surprise to users of the functions, it is almost always better to define a function-template specialization (Section 16.6, p. 671) than to use a nontemplate version.

设计既包含函数模板又包含非模板函数的重载函数集合是困难的,因为可能会使函数的用户感到奇怪,定义函数模板特化(第 16.6 节)几乎总是比使用非模板版本更好。
 



Exercises Section 16.7
Exercise 16.61: Implement the three versions of compare. Include a print statement in each function that indicates which function is being called. Use these functions to check your answers to the remaining questions.

实现 compare 函数的三个版本。在每个函数中包含一个输出语句,指出正在调用哪个函数。使用这些函数检查对其余问题的回答。
 
Exercise 16.62: Given the compare functions and variables defined in this section, explain which function is called, and why, for each of these calls:

对于本节定义的 compare 函数和变量,解释下面每个函数调用中,哪个函数被调用以及为什么。

     compare(ch_arr1, const_arr1);
     compare(ch_arr2, const_arr2);
     compare(0, 0);


 
Exercise 16.63: For each of the following calls, list the candidate and viable functions. Indicate whether the call is valid and if so which function is called.

对于下面的每个调用,列出候选函数和可行函数,指出调用是否有效,以及如果有效,调用哪个函数。

     template <class T> T calc(T, T);
     double calc(double, double);
     template <> char calc<char>(char, char);
     int ival; double dval; float fd;
     calc(0, ival);         calc(0.25, dval);
     calc(0, fd);           calc (0, 'J');
     }


 
 

  
     



pengfoo 2013-01-18
  • 打赏
  • 举报
回复
看了这么多分就进来了……
mymtom 2013-01-18
  • 打赏
  • 举报
回复
引用 1 楼 lile1234_show 的回复:
好多英文.. 这是函数模版的重载?
确实是函数模板重载,我手上没有中文版,就把英文版的贴上来了,不知道中文版里是怎么写的!
lee_鹿游原 2013-01-18
  • 打赏
  • 举报
回复
好多英文.. 这是函数模版的重载?
pengfoo 2013-01-18
  • 打赏
  • 举报
回复
引用 12 楼 mymtom 的回复:
谢谢大家! 给分也是个麻烦事情啊,搞了5分钟才搞好。 有没有漏给分的?如果有的话,说一声,我会再开贴补偿的!
早知道我多要点分啊
mymtom 2013-01-18
  • 打赏
  • 举报
回复
谢谢大家! 给分也是个麻烦事情啊,搞了5分钟才搞好。 有没有漏给分的?如果有的话,说一声,我会再开贴补偿的!
mymtom 2013-01-18
  • 打赏
  • 举报
回复
引用 7 楼 lvjing_CSDN 的回复:
我觉得书上错了,template <typename T> int compare(const T&, const T&);的模板行惨是引用类型,如果传递的是数组的话,compare的两个行参都是引用类型,要求两个数组的维度都相同,但是树上给的两个数组的维度不一样,无法用来实例化。不过把这个函数的行惨定义位非引用类型就可以了,或者把那两个数组的维度改成相同……
++ 由于是引用,所以不会把数组转为指针。
mymtom 2013-01-18
  • 打赏
  • 举报
回复
又找到一点线索,引用和普通类型有区别
template <typename T> int compare(const T&, const T&);
改为
template <typename T> int compare(const T, const T);
就可以了,原因应该是: 在实例化的时候,如果模板参数为引用的话,是不会把数组转为指针的。 请看下面的红色部分 16.2.1. Template Argument Deduction Limited Conversions on Type Parameter Arguments In general, arguments are not converted to match an existing instantiation; instead, a new instance is generated. There are only two kinds of conversions that the compiler will perform rather than generating a new instantiation: * const conversions: A function that takes a reference or pointer to a const can be called with a reference or pointer to nonconst object, respectively, without generating a new instantiation. If the function takes a nonreference type, then const is ignored on either the parameter type or the argument. That is, the same instantiation will be used whether we pass a const or nonconst object to a function defined to take a nonreference type. * array or function to pointer conversions: If the template parameter is not a reference type, then the normal pointer conversion will be applied to arguments of array or function type. An array argument will be treated as a pointer to its first element, and a function argument will be treated as a pointer to the function's type.
源码下载地址: https://pan.quark.cn/s/a4b39357ea24 Altium Designer 18是一款功能丰富的电子设计自动化工具,其集成了电路原理图绘制、PCB布局规划、三维视图展示、电路仿真分析以及生产文件生成等多项核心功能,为电子工程师们提供了一个全面的硬件设计解决方案。该软件的官方中文指导材料系统地阐述了从项目初始阶段到最终完成的全过程操作方法。 在“AD18 官方中文指导材料”中,使用者可以掌握以下核心内容要点: 1. **系统配置与界面认知**:熟悉Altium Designer 18的工作平台,涵盖菜单选项、工具栏配置、工作区域安排,以及个性化工作界面的设定方法。 2. **项目创建流程**:掌握如何建立新的项目工程,包括工程参数配置、项目模板选取,以及项目文件的添加操作。 3. **电路图绘制技术**:学习电路原理图的绘制流程,包括元件库的维护管理、元件放置技巧、连接线路绘制、属性编辑操作,以及网络表的自动生成方法。 4. **元件库构建与管理**:了解如何建立自定义元件库,执行元件的导入与导出任务,以及利用Altium Designer自带的元件资源库。 5. **PCB布局设计方法**:掌握PCB设计的基本准则,如元件布局策略、布线技巧、层叠结构调整、布线规则优化,以及冲突检测与短路处理技术。 6. **设计规范与约束条件**:理解设定设计规范和电气约束条件的关键性,包括间距参数设定、焊盘尺寸规格、过孔尺寸要求等,以及运用规则检查进行设计验证的流程。 7. **三维模型整合应用**:学习如何将三维模型与PCB设计内容相结合,以实现更为直观的机械配合验证。 8. **电路性能仿真技术**:掌握使用Altium Des...
源码链接: https://pan.quark.cn/s/a4b39357ea24 ### 接口测试知识要点说明 #### 一、接口测试的定义及分类 1. **概念阐释**: - 接口测试作为软件测试的关键环节,主要对系统之间的交互点进行验证。 - 它旨在核实接口的正确性、稳定性和功能性,保障各个系统组件能够依照预期执行交互操作。 2. **实施情境**: - 适用于多系统联合开发的环境。 - 适用于包含多个子系统的复杂应用系统开发过程。 3. **适用范围**: - 为其他系统提供支持的底层基础架构系统。 - 负责协调中心服务的系统架构。 4. **分类标准**: - **模块接口测试**:通常作为单元测试的一部分,适用于独立构建的功能模块。 - **Web接口测试**: - **服务端接口测试**:针对客户端与服务器端之间的接口进行验证。 - **外部接口测试**:对第三方提供的接口进行测试,例如支付平台提供的授权登录接口。 5. **测试角度**: - **接口功能验证**:核实接口功能是否满足预期要求。 - **接口性能评估**:衡量接口的处理能力及响应时间。 - **接口稳定性考察**:检测接口在长时间运行中的表现情况。 - **接口安全检测**:确保接口能够抵御非法访问或数据篡改。 6. **测试手法**: - **参数细致测试**:深入测试接口的输入参数和输出结果。 - **场景模拟测试**:依据实际业务场景进行测试验证。 #### 二、接口测试的详细流程 1. **测试规划**: - 明确测试范围、目标及所需资源。 - 规划测试策略,选择适宜的工具和技术手段。 2. **测试用例设计**: - 依据需求文档和接口规格文档设计测试用例。 - 覆...

65,211

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧