2

在“C++ 模板 - 完整指南”一书的部分2.4 Overloading Function Templates中,您将找到以下示例:

// maximum of two int values
inline int const& max (int const& a, int const& b)
{
    return a < b ? b : a;
}
// maximum of two values of any type
template <typename T>
inline T const& max (T const& a, T const& b)
{
    return a < b ? b : a;
}
// maximum of three values of any type
template <typename T>
inline T const& max (T const& a, T const& b, T const& c)
{
    return max (max(a,b), c);
}
int main()
{
    ::max(7, 42); // calls the nontemplate for two ints (1)
}

然而,在附录 B 的 B.2 简化重载解决方案中,作者指出:

请注意,重载决议发生模板参数推导之后,... (2)

根据(2)::max(7,42)应该max<int>通过参数推导调用。

4

4 回答 4

4

如果函数都完全匹配,包括cv限定符,编译器将在重载解析中更喜欢非模板函数。

因此,这里将选择非模板,即使模板化函数本质上是相同的。

编辑:

在标准草案 N3485 中,我发现了这一点:

13.3.3 最佳可行函数[over.match.best]

鉴于这些定义,如果对于所有参数 i,ICSi(F1) 不是比 ICSi(F2) 更差的转换序列,则可行函数 F1 被定义为比另一个可行函数 F2更好的函数,然后

...

F1 是非模板函数,F2 是函数模板特化,或者,如果不是,

— F1 和 F2 是函数模板特化,根据 14.5.6.2 中描述的偏序规则,F1 的函数模板比​​ F2 的模板更特化。

...

于 2013-03-04T18:21:01.717 回答
3

根据(2)::max(7,42)应该max<int>通过参数推导调用。

不。想一想,要进行重载解析(也就是选择最佳匹配),编译器首先需要知道所有可用的重载并能够比较它们。请注意,函数模板本身并不是一个有效的函数,它首先需要被实例化以创建一个真正的函数。

这意味着,首先,编译器查看所有名为 的函数模板max,尝试为每个模板推导模板参数,然后对实例化函数和非模板函数进行重载解析。

这是函数的可视化(为简洁起见,省略了 cv 限定符):

                    int max(int, int);
template<class Arg> Arg max(Arg, Arg);
template<class Arg> Arg max(Arg, Arg, Arg);

让我们来看看调用::max(7, 42)

首先,编译器看到有三个候选函数。但是,它不能只将第一个重载max与其他两个进行比较——这就像比较苹果和橙子一样。相反,它首先需要从功能模板蓝图中“印出”一个真正的功能。在我们的例子中,这是通过模板参数推导发生的:

int max(int, int); // originally non-template
int max(int, int); // originally template
int max(int, int, int); // not enough arguments, invalid

由于参数/参数计数不匹配,第三个重载被抛出,我们减少到两个。从重载解决方案的角度来看,两者都是平等的——但请稍等!现在有一条规则说明:

§13.3.3 [over.match.best] p1

[...] 鉴于这些定义,如果 [...],一个可行函数F1被定义为比另一个可行函数更好的函数F2

  • F1是一个非模板函数并且F2是一个函数模板特化,
于 2013-03-04T18:36:48.087 回答
2

模板参数推导重载决议后发生之间

1) inline int const& max (int const& a, int const& b);

2) template <>
   inline int const& max (int const& a, int const& b)

在这种情况下 1) 按照 C++ 标准 13.3.3 中的规定调用。1(草案 n3092)。

msdn 也明确指出:

如果非模板函数与模板函数同样匹配,则选择非模板函数

http://msdn.microsoft.com/en-us/library/s016dfe8%28v=vs.80%29.aspx

于 2013-03-04T18:23:56.547 回答
1

根据 C++11 标准的第 13.3.3/1 段(重载决议上下文中的“最佳可行函数”):

定义 ICSi(F) 如下:

— 如果 F 是静态成员函数,ICS1 (F) 被定义为对于任何函数 G,ICS1 (F) 既不好也不差于 ICS1 (G),并且对称地,ICS1 (G) 既不好也不差于ICS1 (F)132;除此以外,

— 令 ICSi(F) 表示将列表中的第 i 个参数转换为可行函数 F 的第 i 个参数的类型的隐式转换序列。13.3.3.1 定义了隐式转换序列,13.3.3.2 定义了它意味着一个隐式转换序列比另一个转换序列更好或更差。

鉴于这些定义,如果对于所有参数 i,ICSi(F1) 不是比 ICSi(F2) 更差的转换序列,则可行函数 F1 被定义为比另一个可行函数 F2 更好的函数,然后

— 对于某些参数 j,ICSj(F1) 是比 ICSj(F2) 更好的转换序列,或者,如果不是,

— 上下文是通过用户定义的转换(见 8.5、13.3.1.5 和 13.3.1.6)和从 F1 的返回类型到目标类型(即被初始化的实体的类型)的标准转换序列进行的初始化是比从 F2 的返回类型到目标类型的标准转换序列更好的转换序列。[...]

F1 是非模板函数,F2 是函数模板特化,或者,如果不是,

— F1 和 F2 是函数模板特化,根据 14.5.6.2 中描述的偏序规则,F1 的函数模板比​​ F2 的模板更特化。

这意味着在重载决议的上下文中,当通过实例化函数模板(因此,在类型推导之后)生成的函数与非模板函数同样好匹配时,非模板函数是首选。

于 2013-03-04T18:35:07.173 回答