在“C ++模板 - 完整指南”一书中似乎存在矛盾

时间:2013-03-04 18:14:44

标签: c++ templates template-deduction

在“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 个答案:

答案 0 :(得分:4)

如果函数既完全匹配又包含cv限定符,编译器在重载解析时会更喜欢非模板函数。

因此,非模板将在此处被选中,即使模板化函数基本上相同。

编辑:

在标准草案N3485中我发现了这个:

13.3.3最佳可行功能[over.match.best]

  

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

...

  

- F1是非模板函数,F2是函数模板特化,或者,如果没有,

     

- F1和F2是功能模板特化,根据14.5.6.2中描述的偏序规则,F1的功能模板比F2的模板更专业。

...

答案 1 :(得分:3)

  

根据(2)::max(7,42)应通过参数扣除来调用max<int>

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

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

这是功能的可视化(为了简洁省略了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是函数模板特化,
  •   

答案 2 :(得分:2)

模板参数扣除后,重载决策发生在

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

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

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

Msdn也明确表示:

  

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

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

答案 3 :(得分:1)

C ++ 11标准中的每段13.3.3 / 1(在重载解析的上下文中为“最佳可行功能”):

  

如下定义ICSi(F):

     

- 如果F是静态成员函数,则定义ICS1(F)使得ICS1(F)既不好也不差   对于任何函数G,ICS1(G),对称地,ICS1(G)既不比ICS1(F)132更好也不差;   否则,

     

- 让ICSi(F)表示隐式转换序列,它将列表中的第i个参数转换为   有效函数F的第i个参数的类型.13.3.3.1定义了隐式转换序列和   13.3.3.2定义了一个隐式转换序列对于更好的转换序列意味着什么   或者转换顺序比另一个更差。

     

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

     

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

     

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

     

- F1是非模板功能,F2是功能模板专业化,或者,如果不是,

     

- F1和F2是功能模板专精,F1的功能模板更专业   根据14.5.6.2中描述的偏序规则,比F2的模板。

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