函数模板中从调用点到模板参数列表的类型的传递替换是define还是typedef

本文深入探讨了C/C++中define与typedef在处理const与指针时的不同行为,以及函数模板实例化时的类型传递过程。通过具体代码示例,详细解释了两者在预编译和编译阶段的行为差异,以及在特例化过程中如何保持一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.区分define以及typedef:

首先一点,大家都可以答得上来,define在预编译阶段处理,typedef在编译阶段处理.
来看下面的这个例子:
明确一点:const修饰的是离它最近的类型

#define T int
typedef int T;
const T a;
在这里没什么区别,但是当const后面有*的时候就很明显了.

#define T char*
typedef char* T;
const T b;
不论是define还是typedef最终看到的是const char* b;

对于define:

尽管在预编译时经过字符串替换后到达编译阶段编译器看到就是const char*b
但是编译器不会将char*看做是一个整体,在与const结合的时候自然会和char结合,
所以,编译器保护的是*b

对于typedef:

对于typedef就不一样了,他是类型替换而不是字符替换,它在编译阶段发生的
编译阶段编译器看到的就是const T b,而T正是我们char*

所以,当与const结合的时候,编译器自然修饰的是T,也就是char*,保护的自然是b

所以,总结一句话,define和我们平时见到的const与指针结合时规范是一样的,修饰的是离const最近的类型,但是typedef不一样,编译器会将重定义的类型看做是一个整体,不会将这个整体再去拆分,这就是区别.

使用typedef时需要注意一种情景:

在我们c/c++有一种类型叫做unsigned int,实际上这是两个类型的组合,不对吗?

  1 #include <iostream>
  2 using namespace std;
  3 
  4 typedef int T;
  5 int main()
  6 {
  7     unsigned T val = 0;
  8     return 0;                                                                                     
  9 }

如果你看到这篇文章,你可以去试一下上面代码能不能编译通过?

如果编译通过了,那意思就是编译器允许类似于这样double int val = 100  ????
自然是不行的啦

#include <iostream>
using namespace std;clear

#define T int

int main()
{
	unsigned T val = 0;
	return 0;
}
这样就可以顺利编译通过了.
因为预编译阶段unsigned T 和我们自己定义时写的unsigned int没区别,这样自然是支持的

二.函数模板的实例化时传递类型给模板参数列表的时候是typedef的过程还是define:

#include<iostream>
using namespace std;

template<typename T>
bool com(const T a, const T b)
{
	cout << "template<typename>" << endl;
	return a > b;
}

int main()
{
	com<char*>("hello","world");
	return 0;
}

为什么需要特例化:
对于字符串的比较来说,我们肯定不能通过比较字面值判断字符串的大小,否则成比较地址大小了 ~. ~,函数模板已经不能满足我们的对于char类型的需求了,这个时候需要一个模板针对char的特例化版本。

template<>
bool com<char*>(const char*a, const char*b)
{
	cout << "template<>" << endl;
	return strcmp(a,b)>0 ? true:false;
}

然后,我们去编译,编译器报错:

“bool (__cdecl *com(char *))(const char *,const char *)”不是函数模板的专用化

原因是这样的:

原函数模板:
template<typename T>
bool com(const T a, const T b)
在原模板中,const修饰的是a和b


模板特例化版本:
template<>
bool com<char*>(const char*a, const char*b)
在特例化版本中,const 修饰的是*a和*b  这样一来,特例化版本就违背了原模板的初衷
原模板保护了a和b,特例化保护了*a和*b,自然编译不过

修改正确,是的const保护a和b,而不是带*的a和b:

//正确的显式专用化
template<>
bool com<char*>(char* const a, char* const b)
{
	cout << "template<>" << endl;
	return strcmp(a,b)>0 ? true:false;
}

总结:

  • 实例化点类型到模板参数类型的替换是一个typedef的过程,不论T是什么类型,int,float还是char*,传递过去一定是typedef的过程,如果有const修饰,一定修饰的是T这个整体。
  • 保证特例化中原型的规则和原模板原型的规则一致。

补充一点:

  1. 不管是const还是volitle,都是一样的规则,因为volitle也是构成重载的要素;
  2. 不管是类模板还是函数模板,原模板中const修饰是谁,在特例化中就要注意,不能将const修饰的改变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值