函数模板(function template)

作者:jicanmeng

时间:2017年06月04日


先看一个程序:

#include <iostream>

using namespace std;

const int max(const int x, const int y)
{
    return (x > y) ? x : y;
}
const double max(const double x, const double y)
{
    return (x > y) ? x : y;
}
const char max(const char x, const char y)
{
    return (x > y) ? x : y;
}

int main()
{
    int i = max(3, 7);
    std::cout << i << '\n';

    double d = max(6.34, 18.523);
    std::cout << d << '\n';

    char ch = max('a', '6');
    std::cout << ch << '\n';

    return 0;
}

以下是运行结果:

[jicanmeng@andy tmp]$ ./a.out
				7
				18.523
				a
			[jicanmeng@andy tmp]$

要实现数据类型相同的两个变量的比较,需要定义三个max()函数。这三个max()函数,除了数据类型不同,别地方都是完全相同的。如果还有其它类型的数据,那么代码就会非常庞大并且难以维护。为了解决这个问题,c++引入了函数模板。如下面代码所示:

#include <iostream>
//#include <algorithm>	//这个标准库中定义了max()函数模板,所以如果包含本头文件,就会和下面的max()模板的定义冲突

using namespace std;

template <typename T>  // this is the template parameter declaration
const T& max(const T& x, const T& y)
{
    return (x > y) ? x : y;
}

int main()
{
    int i = max(3, 7);
    std::cout << i << '\n';

    double d = max(6.34, 18.523);
    std::cout << d << '\n';

    char ch = max('a', '6');
    std::cout << ch << '\n';

    return 0;
}

上面代码中,T 被称为template type parameter。第5行代码中,template后面的<>中包含了所有的template type parameter。

有几点需要注意:

1. 可以定义一个template type parameter,也可以定义多个。例如:

template <typename T1, typename T2>
// template function here
    其中,typename关键字也可以使用class关键字代替,意思是相同的。

2. 由于传递给T的可能也是class类型的对象,为了防止不必要的拷贝,通常使用引用类型。learncpp.com上面的描述如下:

One final note: Because the function argument passed in for type T could be a class type, and it’s generally not a good idea to pass classes by value, it would be better to make the parameters and return types of our templated function const references. 所以就写成了下面的形式:

template <typename T>
const T& max(const T& x, const T& y)
{
    return (x > y) ? x : y;
}

3. 编译器遇到max(3,7)时,会去寻找有没有max(int, int)函数。如果没有此函数,会寻找有没有对应的模板可以创建max(int, int)函数:如果有模板,那么会创建一个max(int, int)函数,这称为模板的实例(function template instance)。

4. 模板的类型参数如果传入class类型的变量, 要注意运算符的重载。

可以看两个例子:

#include <iostream>

using namespace std;

template <typename T>  // this is the template parameter declaration
const T& max(const T& x, const T& y)
{
    return (x > y) ? x : y;
}

class Cents
{
private:
    int m_cents;
public:
    Cents(int cents)
        : m_cents(cents)
    {
    }
    friend bool operator>(const Cents &c1, const Cents &c2) {
        return (c1.m_cents > c2.m_cents) ? true : false;
    }
    int getCents() {
        return m_cents;
    }
};

int main()
{
    Cents nickle(5);
    Cents dime(10);

    Cents bigger = max(nickle, dime);
    std::cout << "bigger number is " << bigger.getCents() << std::endl;

    return 0;
}

上面的这个例子就说明了2,3,4里面的知识点。由于函数模板有>的操作,所以必须对class CPoint类型的对象实现>运算符重载。如果我们在模板的参数和模板的返回值中没有使用引用变量,那么就会有拷贝构造函数的调用。使用了引用变量,减少了内存拷贝,提高了程序运行的效率。

函数模板的定义中,也可以出现固定的数据类型。如下面的例子:

#include <iostream>

using namespace std;

template <class T>
T average(T *array, int length)
{
    T sum = 0;
    for (int count = 0; count < length; ++count)
        sum += array[count];

    sum /= length;
    return sum;
}

class Cents
{
private:
    int m_cents;
public:
    Cents(int cents)
        : m_cents(cents)
    {
    }

    friend bool operator>(const Cents &c1, const Cents &c2) {
        return (c1.m_cents > c2.m_cents);
    }
    friend ostream& operator<< (ostream &out, const Cents &cCents) {
        out << cCents.m_cents << " cents ";
        return out;
    }
    Cents & operator+= (Cents &c1);
    Cents & operator/= (int length);
};

Cents & Cents::operator+= (Cents &c1) {
    m_cents += c1.m_cents;
    return *this;
}

Cents & Cents::operator/= (int length) {
    m_cents /= length;
    return *this;
}

int main()
{
    int array1[] = { 5, 3, 2, 1, 4 };
    std::cout << average(array1, 5) << '\n';

    double array2[] = { 3.12, 3.45, 9.23, 6.34 };
    std::cout << average(array2, 4) << '\n';

    Cents array3[] = { Cents(5), Cents(10), Cents(15), Cents(14) };
    std::cout << average(array3, 4) << '\n';

    return 0;
}

参考资料

  1. <<C++实用教程>> 电子工业出版社 郑阿奇 主编 丁有和 编著
  2. The C++ Tutorial:
    http://www.learncpp.com/cpp-tutorial/131-function-templates/
    http://www.learncpp.com/cpp-tutorial/132-function-template-instances/