typename使用场合
1、在模板定义里表明气候的参数是类型参数
//函数模板
template<typename T, int a, int b>
int funcadd(T c) { };
//类模板
template<typename T, int b>
class myvector { };
注意这里的typename可以写成class
2、使用类的类型成员,用typename标志这是一个类型。
::作用域运算符 :1、访问类的静态函数成员 2、访问类型成员myiterator(是一个由typedef定义的类型)
//迭代器
template<typename T>
typename myvector<T>::myiterator myvector<T>::mybegin()
//这里的typename是必须的,如果不加typename编译器会将myvector<T>::myiterator当成是一个静态数据成员
{
}
这里typename是必须的,告诉编译器,这个名字是一个类型,这里的typename不能换成class
template<typename T>
typename T::size_type getlength(const T &c)
{
}
string::size_type size = getlength(mytest);
当使用类型模板参数 T::类型成员(<T>::类型成员) 时,前面都要加typename
函数指针做其他函数的参数
函数指针要当做函数的参数时:
typedef int(*FunType)(int, int);
用 typedef 相当于定义了一个函数指针类型,定义类型时必须用typedef
void testfunc(int i, int j, FunType funcpoint)
{
funcpoint(i, j);//相当于调用函数,funcpoint
}
mf(int i, int j)
{
int result = i + j;
}
int main()
{
testfunc(1 ,2, mf);
}
特殊写法
template<typename T, typename F>
void testfunc(const T &i, const T &j, F funcpoint)
{
cout << funcpoint << endl;
}
class TC
{
public:
void opreator() const
{
}
}
int main()
{
TC tc1;
void (*funcp)();
testfunc(1, 2, funcp);
testfunc(1, 2, tc1);
testfunc(1, 2, TC());
}
可调用对象
圆括号就是函数调用的标记,()有一个称呼叫做“函数调用运算符”
如果在类中重载函数调用运算符,那么就可以想使用函数一样使用该类对象。对象(实参);
class biggerthanzero
{
public:
biggerthanzero(int u)
{
}
public:
int operator()(int value) const //const非必须,根据是否需要改变类成员而定
{
if (value < 0) return 0;
return value;
}
int operator()(int value1, int value2) const //const非必须,根据是否需要改变类成员而定
{
if (value < 0) return 0;
return value;
}
}
int main()
{
biggerthanzero obj(2); //这里实在执行对象初始化
int result = obj(100); //这里调用重载()运算符
int result = obj.operator()(200);
}
如何使用函数调用运算符
1、定义一个该类对象。
2、像函数一样使用该对象,也就是()中增加实参列表。
结论:只要这个对象所属的类重载了()“函数调用运算符”,那么这个类对象就变成了可调用的了,而且可以调用多个版本的(),只要在参数的类型和数量上有差别。
这个类重载了(),该类的对象就多了个名字,“函数对象”,因为可以调用这种对象,或者说这些对象可以像函数一样被调用。
不同对象的相同调用形式
int echovalue(int value)
{
if (value < 0) return 0;
return value;
}
函数echovalue和 biggerthanzero重载的(),这两个东西,调用参数和返回值相同,就叫做“调用形式相同”。
一种调用形式 对应 一个函数类型:int(int)
1、echovalue函数。
2、重载了函数调用运算符的biggerthanzero类对象。
把这些可调用对象指针保存起来,目的是方便我们随时调用这些可调用对象。这个感觉像C语言的函数指针
map<string, int(*)(int)> myoper;
myoper.insert({"ev", echovalue});
myoper.insert({"ev", obj}); //报错,说明编译器没有把这个类对象看成是一个函数
标准库function
function模板:要提供模板参数来表示该function类型能够表示的对象的调用形式。
#include <function>
function<int(int)> //声明了一个function()类型,用来代表一个可调用对象,它所代表的这
//个可调用对象是:接受一个int型参数并返回int类型。
function<int(int)> f1 = echovalue; //可以,放函数指针
function<int(int)> f2 = obj; //可以,放类对象
function<int(int)> f3 = biggerthanzero(); //直接放类对象也可以
f1(2);
f2(2);
f3(2);
map<string, func<int(int)>> myoper = {
{"ev", echovalue},
{"obj1", obj}
}
myoper["ev"](12); //调用函数
如果echovalue有重载就无法放倒function<>中
我们可以通过定义函数指针来解决。
int (*fp)(int) = echovalue;
function<int(int)> f1 = fp;
默认模板参数
1、类模板,类模板名后边必须提供额外信息。<>表示这是一个模板;默认值参数规则与函数的参数列表默认值书写规则一致
2、函数模板,老标准只能为类模板提供默认参数,C++11可以为函数模板提供默认参数。
template<typename T, typename F=TC>
void testfunc(const T &i, const T &j, F funcpoint = F())
{
cout << funcpoint(i, j) << endl;
}