模板与泛型 —— 函数指针作为模板参数

2020-05-17  本文已影响0人  从不中二的忧伤
一、typename 的用法

1、typename 和 class 在模板定义中,声明模板参数为类型参数时,可以互换。

template<typename T>
T Add(T val1, T val2)

template<class T>
T Add(T val1, T val2)

2、使用类的类型成员时,用 typename 标识其后跟的是个类型。
例一

template<typename T>
class myvector
{
public:
    typedef T* myiterator;  // 用 typedef 定义的为类型成员
public:
    myiterator mybegin();  // 返回容器中的第一个元素
};

template<typename T>
// 1. 需要用 myvector<T>:: 访问类型成员 myiterator
// 2. 编译器只有在实例化时才能确定 myvector<T>:: 后面跟着的是类型还是静态成员变量,所以需要用 typename标识其后跟着的是类型。
typename myvector<T>::myiterator myvector<T>::mybegin()
{
    //todo 
}

例二
size_type 为 string / STL 的类型成员, typedef usigned int size_type
typename 表示 T::size_type 返回的也是一个类型

template<typename T>
typename T::size_type getlength(const T& c)
{
    return c.size();
}

string str = "hello world";
cout << getlength(str) << endl;
二、函数指针作其他函数的参数
// 定义函数指针类型
typedef int (*FunType)(int, int);

int myfunc(int val1, int val2)
{
     return val1 + val2;
}

void recvfunc(int i, int j, FunType pf)
{
    cout << pf(i, j) << endl;
}

int main()
{
    recvfunc(1, 2, myfunc);
    return 0;
}
三、函数指针作为函数模板参数

下面的例子中,编译器将模板参数 F 解释成函数指针类型 FunType

typedef int (*FunType)(int, int);

int myfunc(int val1, int val2)
{
     return val1 + val2;
}

template<typename T, typename F>
void tfunc(const T &i, const T &j, F pf)
{
    cout << pf(i, j) << endl;
}

int main()
{
    tfunc(1, 2, myfunc);
    return 0;
}
四、对象作为函数模板参数
template<typename T, typename F>
void tfunc(const T &i, const T &j, F pf)
{
    cout << pf(i, j) << endl;
}

class Test
{
public:
    Test() { cout << "construct" << endl; }
    Test(const Test& t) { cout << "copy construct" << endl; }
    
    int operator()(int v1, int v2) const
    {
        return v1 + v2;
    }
};

int main()
{
    Test t;    // 调用构造函数
    tfunc(1, 2, t);    // 调用拷贝构造函数
}

执行结果:


image.png

上面的程序中,编译器将模板参数 F 解释为 Test 类型对象(因为在 Test 类中重载了括号Test(int, int),所以Test类对象可以当作函数调用的格式使用),并将 t 传递给了 pf (pf相当于临时对象),调用了拷贝构造函数。

使用临时对象:

int main()
{
    tfunc(2, 3, Test());
}

执行结果:


image.png

使用临时对象,则模板函数直接承接此临时对象,省去了拷贝构造过程(也省去一次析构过程),更加节省时空。

五、默认模板参数
类模板

类模板的实例化必须显示声明模板参数(<>不可省略)
类模板的缺省参数

template<typename T=string, int size=10>
class myarray
{
private:
    T arr[size];
};

int main()
{
    // 完全使用模板参数缺省值
    myarray<> arr1;

    // 使用部分模板参数缺省值
    myarray<int> arr2;

    return 0;
}
函数模板

C++11 开始,支持函数模板默认参数
例一: 对象作为函数模板默认参数

class Test
{
public:
    Test() { cout << "construct" << endl; }
    Test(const Test& t) { cout << "copy construct" << endl; }
    
    int operator()(int v1, int v2) const
    {
        return v1 + v2;
    }
};

// 为 F 提供默认参数 Test 类
template<typename T, typename F=Test>
// 为 pf 提供临时对象 F(),即为Test()
void tfunc(const T &i, const T &j, F pf=F())
{
    cout << pf(i, j) << endl;
}

int main()
{
    tfunc(2, 5);
    return 0;
}

例二:函数指针作为函数模板默认参数

typedef int (*FunType)(int, int);

int myfunc(int val1, int val2)
{
    return val1 + val2;
}
// 为 F 提供默认参数 FunType 类型
template<typename T, typename F=FunType>
// pf 默认为 myfunc
void tfunc(const T &i, const T &j, F pf=myfunc)
{
    cout << pf(i, j) << endl;
}

int main()
{
    tfunc(2, 5);
    return 0;
}

例三:函数模板的默认非类型参数

template<int T=10>
void tfunc()
{
    cout << T << endl;
}

int main()
{
    tfunc();     // 输出10
    tfunc<>();  // 输出 10
    tfunc<12>();    // 输出12
    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读