函数模板推导

    最近在整模板函数的时候,在模板匹配的时候被;弄糊涂了,这里通过实验简单记录一下。

#include <iostream>
#include <type_traits>
using namespace std;

// func1
template<typename T>
void printL(T a){
	cout << "call T" << endl;
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}

// func2
template<typename T>
void printL(T& a){
	cout << "call T&" << endl;
	a.printA();
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}

// func3
template<typename T>
void printL(T* a){
	cout << "call T*" << endl;
	
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}

class A{
public:
	void printA(){
		cout << typeid(*this).name() << endl;
	}
};

int main(){
	A a;
	A& ra = a;
	A* pa = &a;
	printL(a);    // expr1
	printL(ra);    // expr2
	printL(pa);	   // expr3
	return 0;
}

对于func1

   如果func1存在,而func2和func3不存在,执行expr1,expr2,expr3,最终输出是

call T
1 1A
1 1A
call T
1 1A
1 1A
call T
0 P1A
0 P1A

也就是原本的a和a的引用在模板函数中都被推倒成类型A,而ra的a的类型都是A。而对于pa,其推到的类型是A*,pa的类型也是A*。

    func1中调用printA方法,即

template<typename T>
void printL(T a){
	cout << "call T" << endl;
	a.printA();
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}

a和ra可以正常使用,printA会输出this类型是A,而pa会报错。

对于func2

如果func2存在,而func1和func3不存在,执行expr1,expr2,expr3,最终输出是

call T&
0 1A
1 1A
call T&
0 1A
1 1A
call T&
0 P1A
0 P1A

a推倒出的类型T是A,a本身的语义类型也是A;ra推导出的类型T是A,但func2参数a本身类型是A&;而pa推导的类型是A*,func2参数a自身的类型是A*&,也就是对A*的引用。

如果想在func2中调用printA的方法,对于a和ra来说,可以直接采用a.printA;而对于pa来说,则需要通过a->printA。

对于func3

如果func3存在,而func1和func2不存在,执行expr1,expr2,expr3,最终输出是

// printL(a);  报错
// printL(ra); 报错
printL(pa);
call T*
0 P1A
1 1A

a和ra都无法找到匹配的,而pa推倒的T是A,而func3本是是A*类型。

对于func1、func2和func3都存在

// printL(a);  报错
// printL(ra); 报错

依然是会报错。

对于func1和func3都存在

call T
1 1A
1 1A
call T
1 1A
1 1A
call T*
0 P1A
1 1A

对于func2和func3都存在

call T&
0 1A
1 1A
call T&
0 1A
1 1A
call T*
0 P1A
1 1A

注意和前一个对比,推到的T类型都是A,但是自身a的语义不一样了。

call auto
1 1A
call auto
1 1A
call auto
0 P1A

如果func4如下

void printL(auto a){
	cout << "call auto" << endl;

	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
}

对于expr1,expr2,expr3来说,自身的语义和a一样。a得到A,ra得到A,pa得到PA,

但是,但是不一样的是

//template<typename T>
void printL(auto a){
	cout << "call auto" << endl;
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
//	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}

class A{
public:
	void printA(){
		cout << is_class<decltype(*this)>::value << " "<<typeid(*this).name() << endl;
	}
};

int main(){
	A a;
	A& ra = a;
	A* pa = &a;
    cout << is_class<decltype(*pa)>::value << " " << typeid(decltype(*pa)).name() << endl;
	printL(*pa);
	return 0;
}

输出结果

0 1A
call auto
1 1A

也就是说本身*pa表达式得到的是A&,在main中不是类,而是引用,用过函数func4传递到a上,形参a的语义就是A了。

    如果把func4改为

void printL(auto& a){
	cout << "call auto" << endl;
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
//	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}
call auto
0 1A
call auto
0 1A
call auto
0 P1A

形参a无法通过decltype推导出类型A。与没有&不同。

如果改为

void printL(auto&& a){
	cout << "call auto" << endl;
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
//	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}
call auto
0 1A
call auto
0 1A
call auto
0 P1A

通过引用折叠,只对右值引用有作用。

如果改为

void printL(auto* a){
	cout << "call auto" << endl;
	cout << is_class<decltype(a)>::value << " " << typeid(decltype(a)).name() << endl;
//	cout << is_class<T>::value << " " << typeid(T).name() << endl;
}

只有指针能调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值