0

0

模板非类型参数怎么用 整型常量与指针作为模板参数

P粉602998670

P粉602998670

发布时间:2025-07-20 11:08:02

|

419人浏览过

|

来源于php中文网

原创

非类型模板参数允许在编译时传递常量值或地址,提升代码安全与效率。1.语法上支持整型、枚举、指针等类型,如template定义固定大小数组;2.指针参数需指向具有外部链接或静态存储期的对象或函数;3.使用时必须确保值为编译时常量表达式,不能是局部变量或非静态成员地址;4.优势包括编译优化、类型安全和无运行时开销,但牺牲了运行时灵活性并可能导致代码膨胀。

模板非类型参数怎么用 整型常量与指针作为模板参数

C++模板,这东西用起来简直是写代码的利器,尤其是那些需要泛型编程的场景。我们最常用的是类型参数,比如std::vector里的int。但今天想聊的,是模板的另一个维度——非类型参数。这玩意儿,说白了,就是你在定义模板的时候,除了可以传类型进去,还能直接把一个常量值或者一个地址(指针)塞进去,让编译器在编译阶段就帮你把一些事情定死。这可不是小把戏,它能让你的代码在某些特定场景下,既安全又高效。

模板非类型参数怎么用 整型常量与指针作为模板参数

要用非类型模板参数,语法上其实挺直观的。你可以在template后面,除了typename T或者class T这种类型参数,再加一个像int N或者MyEnum E,甚至是void(*FuncPtr)()这样的参数。关键点在于,这些参数的值必须在编译时就能确定。

举个最常见的例子,固定大小的数组:

模板非类型参数怎么用 整型常量与指针作为模板参数
template 
class FixedArray {
public:
    T data[Size]; // Size在这里就是编译时确定的
    // ... 其他成员函数
};

// 使用时:
FixedArray arr; // 数组大小10,编译时就定好了
FixedArray anotherArr; // 数组大小5

这里,Size就是一个整型非类型参数。它让FixedArrayFixedArray成为完全不同的类型,编译器能针对不同大小做优化。

再来个指针的例子。虽然指针作为非类型参数在日常业务代码里不那么常见,但在一些底层或者框架设计里,它能派上用场。比如,你想让一个模板类总是操作某个特定的全局变量,或者调用某个特定的全局函数:

模板非类型参数怎么用 整型常量与指针作为模板参数
// 假设有一个全局变量
int global_counter = 0;

// 假设有一个全局函数
void increment_global_counter() {
    global_counter++;
}

template  // 指针作为非类型参数
struct GlobalVarAccessor {
    static void increment() {
        (*Ptr)++; // 通过模板参数访问全局变量
    }
    static int get() {
        return *Ptr;
    }
};

template  // 函数指针作为非类型参数
struct FunctionCaller {
    static void call() {
        Func(); // 通过模板参数调用函数
    }
};

// 使用:
GlobalVarAccessor<&global_counter> accessor;
accessor.increment(); // 编译时就确定了要操作 global_counter

FunctionCaller<&increment_global_counter> caller;
caller.call(); // 编译时就确定了要调用 increment_global_counter

看到没,&global_counter&increment_global_counter都是在编译时就能确定地址的。这让编译器能生成高度特化的代码,甚至可能进行一些激进的优化。当然,这里有个大前提:这些指针必须指向具有外部链接(external linkage)或者静态存储期的对象或函数。本地变量的地址可不行,那是在运行时才确定的。

非类型模板参数:哪些类型能用,又有哪些坑?

非类型模板参数并不是什么类型都能塞进去的。C++标准对它有明确的限制,毕竟它要在编译时就确定下来。

超级简历WonderCV
超级简历WonderCV

免费求职简历模版下载制作,应届生职场人必备简历制作神器

下载

一般来说,你可以用:

  • 整型类型int, long, bool, char等,包括它们的有符号和无符号版本)。这是最常见的,比如上面FixedArraySize
  • 枚举类型enum class或者传统enum)。这在策略选择上很有用,比如根据枚举值选择不同的算法实现。
  • 指针类型。可以是对象指针(包括std::nullptr_t),也可以是函数指针。但这里有个大坑:它必须指向一个具有外部链接(external linkage)或者静态存储期(static storage duration)的对象或函数。换句话说,你不能把一个局部变量的地址传进去,因为局部变量的地址只有在运行时才确定。
  • 引用类型。和指针类似,也必须引用具有外部链接或静态存储期的对象。

从C++20开始,这个限制放宽了,你甚至可以用浮点数和字面量类类型(literal class types)作为非类型参数。但在此之前,主要是上面那些类型。

你可能会遇到的坑:

  • constexpr:如果你传进去的值不是一个编译时常量表达式,编译器会直接报错。比如int x = 10; FixedArray arr; 这就是错的,x不是constexpr
  • 局部变量的地址int local_var = 0; GlobalVarAccessor accessor; 这种写法是绝对不行的,local_var没有外部链接。
  • 非静态成员的地址:你不能把一个类的非静态成员变量或成员函数的地址作为非类型参数,因为它们依赖于特定的对象实例。

所以,在用非类型参数的时候,脑子里得绷着一根弦:这玩意儿,编译时就得给我把值固定住!

运行时参数 vs. 非类型模板参数:什么时候用谁?

有时候,我们会纠结一个值到底是用模板参数传进去,还是在构造函数或者成员函数里作为运行时参数。这其实是个设计哲学上的选择,没有绝对的对错,只有适不适合。

非类型模板参数的优势非常明显:

  • 编译时优化:因为值在编译时就确定了,编译器可以做更多的优化,比如常量折叠、死代码消除,甚至生成完全特化的代码。这通常意味着更好的运行时性能。
  • 类型安全:这个值是类型签名的一部分。FixedArrayFixedArray是两个完全不同的类型。这意味着你不可能不小心把一个10个元素的数组当成20个元素的来用,编译器会帮你抓出这种错误。
  • 无运行时开销:参数的值直接嵌入到生成的代码中,运行时不需要额外的存储空间来保存这个值,也没有参数传递的开销。

但它也有局限性:

  • 缺乏运行时灵活性:一旦编译完成,这个值就固定了,你不能在程序运行时改变它。如果你需要根据用户输入或者其他运行时条件来决定某个值,那非类型模板参数就无能为力了,你必须使用运行时参数。
  • 代码膨胀:如果你的非类型参数有很多不同的值,编译器会为每个不同的值生成一份独立的类型和代码。这可能导致最终的可执行文件体积

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1435

2023.10.24

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

73

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

522

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

49

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

190

2025.08.29

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

173

2023.11.23

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

65

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SQL 教程
SQL 教程

共61课时 | 3.2万人学习

C# 教程
C# 教程

共94课时 | 5.7万人学习

C 教程
C 教程

共75课时 | 3.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号