[编程语言]C++函数模板笔记-1

函数模板

函数模板的基本形状

    template <typename T>
    T fun(T val1, T val2)
    {
        return val1*val2;
    }

开头的template表示接下来的函数是一个模板函数

其中的typename也可以用class来替代.

T在之后的函数里可以用来代指函数类型.你也可以把它改成其他名字,然后用到它的地方也改成对应的名字就行.

总之,必须以template这个关键字开头,后面一个<typename T>或者<class T>, T只是一个标识符,不是固定搭配,可以任意写.

再之后就是写你想要的函数.

要注意,函数里用到的操作符对于传进去的参数的类型必须要合法

例如, 如果传进去一个string,那里面就不能对这个变量用减号-,因为string没有减法.(编译器可以发现这个错误,所以这样的代码是编译不过的)

C++的max()等函数使用了这种方式,所以你会发现max()的两个参数必须相同.

实例化

在编译的时候,编译器会用具体的类型来代替类型模板参数,这个过程叫做实例化.

其实就是生成指定了实际类型的函数,来替换模板函数.

但是只会生成需要的类型,而不是每种类型都来一个.

对于以上的那个模板函数,程序在编译的时候,会检查这个函数在代码中被传入了什么类型,然后对于每种用到的类型,生成一个函数来替换原来的模板函数.

例如,如果程序中的main如下:

int main()
{
    fun((int)1, (int)2);
    fun((double)1.0, (double)2.0);
}

那么就只会生成int fun(int a, int b)double fun(double a, double b).

使用多个类型

你可以在模板函数里用多个类型,形状如下

template <typename X, typename Y>
void fun(X tv1, Y tv2)
{
    cout << tv1 << ' ' << tv2 << endl;
}

这时,调用像这样fun(1, 2.0).

手动指定类型

但是使用多个类型的时候,编译器不一定能推测出到底是哪个对应什么类型,例如

template <typename X, typename Y, typename Z>
Z fun(X a, Y b)
{
    return a*b;
}

如果你这样调用int tmp = fun(1, 2.0), 就会运行错误,因为编译器推测不出Z是什么类型.

所以你应该在调用的时候,通过尖括号指定类型,像这样int tmp = fun<int, double, int>(1, 2.0).

仅仅指定一部分类型

其实我们可以只指定推测不出来的类型,而不指定能够推测的类型.

要怎么做,我们可以把推测不出来的类型放到最前面,如下

template <typename Z, typename X, typename Y>
Z fun(X a, Y b)
{
    return a*b;
}

那么我们可以这样调用int tmp = fun<int>(1, 2.0).

尖括号里面只要写一个int,用来指定推测不出来的Z就好了.

注意,一定要把需要指定的参数堆到最前面,不能跳着指定的.

auto推断返回值

很多时候,推测不出的是返回值,我们可以用auto代替返回值,形状如下

template<typename X, typename Y>
auto fun(X x, Y y)
{
    return x*y;
}

返回类型后置语法

有这样一种操作

template<typename X, typename Y>
auto fun(X x, Y y) -> decltype(x*y)
{
    return x*y;
}

这里auto并没有进行类型推导.

空函数列表的作用

有时候一个模板函数本身已经有能力推测出所有类型了,我们没有必要再加尖括号.

但如果存在一个同名的普通函数fun(int a, int b), 那么这样调用fun(1,2)的时候,就会优先调用普通函数.

如果我们加一个尖括号fun<>(1, 2),虽然没有含义,但是可以让它调用模板函数.

原文地址:https://www.cnblogs.com/zzidun-pavo/p/14269847.html