模板推演和重载

Template deduction and overloading

本文关键字:重载      更新时间:2023-10-16

这是入门 c++ 5th 中的一个练习:

template <typename T> void f(T);                   //1
template <typename T> void f(const T*);            //2
template <typename T> void g(T);                   //3
template <typename T> void g(T*);                  //4
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42); g(p); g(ci); g(p2);
f(42); f(p); f(ci); f(p2);

答案是:

g(42);  //type: int(rvalue) call template 3  T: int          instantiation: void g(int)
g(p);   //type: int *       call template 4  T: int          instantiation: void g(int *)
g(ci);  //type: const int   call template 3  T: const int    instantiation: void g(const int)
g(p2);  //type: const int * call template 4  T: const int    instantiation: void g(const int *)
f(42);  //type: int(rvalue) call template 1  T: int          instantiation: void f(int)
f(p);   //type: int *       call template 1  T: int *        instantiation: void f(int *)
f(ci);  //type: const int   call template 1  T: const int    instantiation: void f(const int)
f(p2);  //type: const int * call template 2  T:int          instantiation: void f(const int *)

我的问题是为什么f(p)赞成f(T)的实例化而不是f(const T *)

简而言之,在重载解析中包含函数模板的规则是:

  1. 名称查找确定一组可见的函数、对象和函数模板。

  2. 集合中的每个函数模板从任何显式参数、推导和/或默认模板参数中确定其模板参数,如果可能,这些参数将被替换以获得一个特定的具体函数签名。 (如果不可能,则只是将函数模板从集合中抛出。 当模板参数推断失败以及将参数替换到签名中失败(也称为"SFINAE"规则)时,可能会发生这种情况。

  3. 这些函数使用正常的重载解析规则进行比较,将来自模板的签名完全视为普通的非模板函数。

  4. 仅当步骤 3 认为其中两个函数不明确时,这些决胜规则才适用:

    一个。如果一个函数签名来自模板,而另一个不是,则认为非模板函数更好。

    二.如果两个函数签名都来自模板,并且一个模板比另一个模板"更专业",则认为更专业的模板更好。 (简而言之,"更专业"本质上意味着我们可以证明对更专业的模板的任何有效参数也是对不太专业的模板的有效参数,但反之则不然。

在本示例的f(p)表达式中,在步骤 2 中,模板 #1 推导T=int*,模板 #2 推导T=int,因此签名为:

void f(int*);        // from 1
void f(const int*);  // from 2

在步骤 3 中,参数p的类型为int*,因此 #1 中的void f(int*);使用标识转换(完全匹配),#2 中的void f(const int*);使用指针转换,因此 #1 中的void f(int*);获胜,并且该函数模板专用化是命名的函数模板专用化。

确实,模板 #2void f(const T*);比模板 #1void f(T);更专业。 但是由于第 3 步决定了答案,我们永远不会进入第 4 步,所以这在这里并不重要。 (步骤 4 确实适用于另一个表达式f(p2)

这不是语言律师的答案,但基本上:

f(T)T=int*完全匹配int*

f(T const*)T=int并不完全匹配int*

完全匹配获胜。