一 推导
- 这里的推导指的是,调用模板函数时由编译器根据上下文来推断所调用的模板函数的模板参数。
二 示例
指针类型推导
- 由于编译器可以自动推导出这个类型也就是三层指针,所以我们没有使用<>传入这个模板函数的类型。
template <typename T>
void baseFunction(T*)
{
qDebug()<<typeid(T).name();
}
int ****pointer = nullptr;
baseFunction(pointer);
数字大小自动推导
- 这里值得注意的是 T(&p): &p是一个引用,引用的是T的类型
- 这里T自动被推导为int,而N被推导为10
- 如果需要手动指出则需要: baseFunction<int,10>(array);
template <typename T,int N>
void baseFunction( T(&p)[N] )
{
qDebug()<<N<<","<<typeid(T).name()<<","<<p[2];
}
int array[10] = {1,2,3,4,5};
char str[100] = "hello world";
baseFunction(array);
类的函数指针推导
- 首先我们定义一个模板
- 因为T2::*t2 是这样调用的,很明显第一个参数其实是一个类的成员函数指针。
template <typename T1,typename T2,typename T3>
void func(T1(T2::*t2)(T3),T3 t3) // T2一定是个类/结构体类型 并且是一个函数 返回值为T1 参数为T3
{
T2 instance;
(instance.*t2)(t3);
qDebug()<<typeid(T1).name()<<" "<<typeid (T2).name()<<" "<< typeid (T3).name();
}
class testFunc
{
public:
int test_Func(int bbb)
{
qDebug()<<bbb;
}
};
- 自动推导:
- 如果上面的类的成员函数我们定义为double,就不能推到成功了,因为在调用时,编译器不能推断出,它是double还是float
func(&testFunc::test_Func,100);
template <int N>
class X
{
public:
typedef int iInt;
void f(int n)
{
qDebug()<<10 + N + n;
}
};
template<int N>
void function(void(X<N>::*p)(typename X<N>::iInt))
{
X<N> x;
(x.*p)(N);
qDebug()<<N;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
function(&X<5>::f);
return a.exec();
}
函数指针类型推导
template <typename T>
void Func(T t1)
{
qDebug()<<typeid (T).name() << "," << t1;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
void(*function)(char) = &Func;
function('A');
return a.exec();
}
类继承的自动推导
- 当调用
Func(m1);
时,Func
被实例化为 Func<M<int>>
,并输出 int
的类型名称。 - 当调用
Func(n1);
时,Func
被实例化为 Func<N<double>>
,但由于 N<double>
是 M<double>
的派生类,所以它能被隐式转换为 M<double>
,进而输出 double
的类型名称。
template <typename T>
class M
{
};
template<typename T>
class N : public M<T>
{
};
template <typename T>
void Func(M<T>)
{
qDebug()<<typeid (T).name();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
M<int> m1;
N<double> n1;
Func(m1);
Func(n1);
return a.exec();
}
右值引用
- 通过这种右值引用T&&,可以智能的处理左值和右值
- 比如如果传进去是左值,int template = 100; 传入template,则被绑定为T &t
- 如果传入是一个 100,则被绑定为 T &&t
template <typename T>
void Func(T && t)
{
qDebug()<<typeid (T).name();
}
int templateA = 100;
Func(templateA);
Func(100);
Func('1');
Func("100");