书中似乎有矛盾"C++ Templates - The Complete Guide"
There seems to be a contradiction in the book "C++ Templates - The Complete Guide"
在《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.2附录B的简化重载解析中,作者声明:
注意重载解析发生在模板实参演绎之后,…(2)
根据(2)
, ::max(7,42)
应通过论证演绎调用max<int>
。
如果两个函数都是精确匹配的,包括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的函数模板更专门化。
…
根据
(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
是函数模板专门化,
模板参数演绎后,
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 par. 1 (Draft n3092)的规定调用。
Msdn也明确指出:
http://msdn.microsoft.com/en-us/library/s016dfe8%28v=vs.80%29.aspx如果非模板函数与模板函数同样匹配,则选择非模板函数
c++ 11标准第13.3.3/1段(重载解析上下文中的"最佳可行函数"):
定义ICSi(F)如下:
—如果F是静态成员函数,则定义ICS1 (F)使ICS1 (F)不优于也不劣于ICS1 (G)对于任何函数G,并且,对称地,ICS1 (G)既不优于也不劣于ICS1 (F)132;否则,
-设ICSi(F)表示将列表中的第i个参数转换为对象的隐式转换序列可行函数f的第i个参数的类型。13.3.3.1定义了隐式转换序列和13.3.3.2定义了一个隐式转换序列是一个更好的转换序列意味着什么
给定这些定义,一个可行函数F1被定义为比另一个可行函数更好的函数F2如果对于所有参数i, 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的模板替换。
这意味着在重载解析上下文中,当通过实例化函数模板生成的函数(因此,在类型推导之后)与非模板函数同样匹配时,首选非模板函数。
- 这对"With a stackless coroutine, only the top-level routine may be suspended."意味着什么
- Doees the 'this' 指针参与虚函数的多态行为
- 为什么我会收到"Run-Time Check Failure #2 - Stack around the variable 'pr' was corrupted"错误?
- 您将如何连接"on the fly"文本+整数并将其传递给函数?
- 如何理解"Temporary objs are destroyed as the last step in evaluating the full-expression"?谁能用一些简单的例子来说明这
- 如何解决C++中声纳库贝静态代码分析错误"Explicitly define the missing copy constructor, move constructor .."
- Configuring the MPEG4MediaSink
- 这在C++ "It does not own the underlying data, and so is cheap to copy or assign"中意味着什么
- What is the std::chrono::time_point equivalent of std::numer
- 如何在数据库程序中添加"reduce the quantity of an item"功能?
- 使用自定义 nodejs 插件时的"The specified module could not be found"
- Boost.Python 和导入 dll,"The specified module could not be found"
- "Build succeeded"但"The breakpoint will not currently be hit"
- 尝试应用肖恩父母谈话"inheritance is the base class of evil"中的模式
- 为什么'allocate in one library and free in the other'是错误的
- ATL OLE DB Consumer Templates 与 Microsoft OLE DB Driver for
- 如何修复此错误"the value of 'x1' is not usable in a constant expression"?static_assert
- Count the digits
- 加载安全区图像"A device attached to the system is not functioning"
- 书中似乎有矛盾"C++ Templates - The Complete Guide"