首页 > 后端开发 > C++ > 正文

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

P粉602998670
发布: 2025-07-20 11:08:02
原创
411人浏览过

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

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

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

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

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

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

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

// 使用时:
FixedArray<int, 10> arr; // 数组大小10,编译时就定好了
FixedArray<double, 5> anotherArr; // 数组大小5
登录后复制

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

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

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

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

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

template <void(*Func)()> // 函数指针作为非类型参数
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++标准对它有明确的限制,毕竟它要在编译时就确定下来。

AiPPT模板广场
AiPPT模板广场

AiPPT模板广场-PPT模板-word文档模板-excel表格模板

AiPPT模板广场 147
查看详情 AiPPT模板广场

一般来说,你可以用:

  • 整型类型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<int, x> arr; 这就是错的,x不是constexpr
  • 局部变量的地址int local_var = 0; GlobalVarAccessor<&local_var> accessor; 这种写法是绝对不行的,local_var没有外部链接。
  • 非静态成员的地址:你不能把一个类的非静态成员变量或成员函数的地址作为非类型参数,因为它们依赖于特定的对象实例。

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

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

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

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

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

但它也有局限性:

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

以上就是模板非类型参数怎么用 整型常量与指针作为模板参数的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

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