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

时间:2018-06-07 09:01:58

标签: c++ stl

#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 ++模板:完整指南[第2版]书

3 个答案:

答案 0 :(得分:6)

正在引发的问题是不会调用非模板重载。

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

答案 1 :(得分:2)

解决方案是:为max<T>专门设置T = int,而不是定义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<int>定义max<T>之后max<int>使用max<T>T = int已经专门化,根据[temp.expl.spec]/6程序将是不正确的,无需诊断。

如果这是您无法承担的风险,您可以使用工具。 SFINAE就是其中之一,并且可以禁止使用<undefined />来调用// Valid: Matrix of String tensors. // Each element might have a different length. byte[][][] matrix = new byte[2][2][]; matrix[0][0] = "this".getBytes("UTF-8"); matrix[0][1] = "is".getBytes("UTF-8"); matrix[1][0] = "a".getBytes("UTF-8"); matrix[1][1] = "matrix".getBytes("UTF-8"); Tensor<String> m = Tensor.create(matrix, String.class); 。这将导致工作程序或编译错误。

答案 2 :(得分:1)

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

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

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

使用自定义类型,感谢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)都会在内部调用非模板重载。

Demo