三个参数函数模板令人困惑的示例

Three argument function template confusing example

本文关键字:函数模板 三个 参数      更新时间:2023-10-16
#include <iostream>
// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
std::cout << "max<T>() n";
return b < a ? a : b;
}
// maximum of three values of any type:
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c); // uses the template version even for ints
} //because the following declaration comes
// too late:
// maximum of two int values:
int max (int a, int b)
{
std::cout << "max(int,int) n";
return b < a ? a : b;
}
int main()
{
::max(47,11,33); // OOPS: uses max<T>() instead of max(int,int)
}

在这个例子中(来自下面提到的书(,我不明白为什么 ::max(47,11,33( 调用期望使用 max(int,int(。所以一个是 2 个参数,另一个是 3 个参数,我认为它应该使用 3 个参数函数定义。

我错过了什么吗?

注:David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor C++ Templates: The Complete Guide [2nd ed.] book

提出的问题是不会调用非模板重载。

max<T>(T a, T b, T c)知道max<T>(T a, T b)但不知道存在整数重载,因为它是在它之后声明的。

解决方案是:专门针对T = intmax<T>,而不是定义int(int, int)函数:

#include <iostream>
template<typename T>
T max (T a, T b)
{
std::cout << "max<T>() n";
return b < a ? a : b;
}
template<>
int max (int a, int b)
{
std::cout << "max(int,int) n";
return b < a ? a : b;
}
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c);
}
int main()
{
::max(47,11,33); // BINGO: uses specialized max<int>()
}

输出:

max(int,int) 
max(int,int) 

不过,如果非模板函数在定义max<T>之后和max<int>专用化之前使用max<int>,这很脆弱,根据[temp.expl.spec]/6程序格式不正确,无需诊断。

如果这是您无法承担的风险,则可以使用一些工具。SFINAE就是其中之一,可以禁止一般max<T>T = int一起称呼。这将导致工作程序或编译错误。

::max(47, 11, 33);实际上是::max<int>(47, 11, 33);

反过来会打电话给::max<int>(::max<int>(47, 11), 33);这可能令人惊讶。

由于int是内置的(因此没有 ADL(,因此在定义max(T, T, T)以允许在模板中调用该版本之前,max(int, int)应该是可见的:

使用自定义类型,借助 ADL,可以在以下之后声明max函数:

template <typename T>
T max (T a, T b)
{
std::cout << "max<T>()n";
return b < a ? a : b;
}
// Should be declared **before** max(T, T, T)
int max(int a, int b)
{
std::cout << "max(int,int) n";
return b < a ? a : b;
}
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c);
}
struct S {};
// Might be declared after max(T, T, T)
S max(S, S)
{
std::cout << "max(S, S)n";
return {};
}

现在,max(0, 1, 2)max(s, s, s)都将在内部调用非模板重载。

演示