非类型模板参数

本文介绍了C++中的非类型模板参数,包括其定义、限制和使用示例。非类型参数可以是整型、指针或引用,但不能是浮点数、类或字符串。实参必须是编译时常量表达式。文章通过多个示例展示了非类型参数在函数模板、类模板以及模板模板参数中的应用。

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

/*
模板除了定义类型参数,我们还可以在模板定义非类型参数。
什么是非类型形参?顾名思义,就是表示一个固定类型的常量而不是一个类型。
固定类型是有局限的,只有整形,指针和引用才能作为非类型形参,
而且绑定到该形参的实参必须是常量表达式,即编译期就能确认结果。

非类型形参的局限:
1.浮点数不可以作为非类型形参,包括float,double。具体原因可能是历史因素,也许未来C++会支持浮点数。
2.类不可以作为非类型形参。
3.字符串不可以作为非类型形参
4.整形,可转化为整形的类型都可以作为形参,比如int,char,long,unsigned,bool,short(enum声明的内部数据可以作为实参传递给int,但是一般不能当形参)
5.指向对象或函数的指针与引用(左值引用)可以作为形参
 
非类型实参的局限:
1.实参必须是编译时常量表达式,不能使用非const的局部变量,局部对象地址及动态对象
2.非Const的全局指针,全局对象,全局变量(下面可能有个特例)都不是常量表达式。
3.由于形参的已经做了限定,字符串,浮点型即使是常量表达式也不可以作为非类型实参
备注:常量表达式基本上是字面值以及const修饰的变量
*/


#include "stdafx.h" 
#include<iostream

<think>好的,我现在需要解释类型模板参数类型模板参数的区别和各自的用途。用户之前已经问过关于`template<size_t N>`的问题,现在他们想更全面地了解两种模板参数的不同。首先,我应该回顾一下之前的回答,确保不重复但补充更多细节。 首先,我需要明确两者的基本定义。类型模板参数是传递类型,比如`typename T`,而类型模板参数传递的是具体的值,比如整数、指针或引用。然后,我需要比较它们的应用场景,比如类型参数用于泛型编程,而类型参数常用于指定大小或常量值。 接着,我应该考虑用户可能的疑问点。比如,为什么需要类型参数?什么时候应该用类型参数?可能用户对两者的选择存在困惑。需要举一些实际的例子,比如std::array使用类型参数来指定数组大小,而std::vector使用类型参数来指定元素类型。 还要注意语法上的区别。类型参数使用`typename`或`class`关键字,而类型参数需要指定具体的类型,比如`int`、`size_t`等。此外,类型参数的值必须在编译时确定,这涉及到constexpr或常量表达式的问题。 可能还需要讨论两者的优缺点。比如类型参数会导致代码膨胀,因为每个不同的值都会生成新的实例,而类型参数则更灵活,但可能需要更多的模板特化。 另外,用户可能对C++20的新特性感兴趣,比如类型模板参数支持浮点数或类类型(需要满足某些条件),这可以稍微提一下,但可能不需要深入,除用户明确问到。 最后,总结两者的核心差异,帮助用户根据需求选择适合的模板参数类型。确保语言通俗易懂,结构清晰,使用示例来辅助说明,比如用数组容器和算法优化的例子。</think>以下是关于C++中**类型模板参数**与**类型模板参数**的对比解析,用表格形式直观呈现核心差异: --- ### **1. 基本定义对比** | 维度 | 类型模板参数 | 类型模板参数 | |--------------------|----------------------------------|------------------------------------| | **传递内容** | 数据类型(如`int`, `std::string`) | 具体的数值(如`5`, 指针,编译期常量)| | **语法形式** | `template<typename T>` | `template<int N>` / `template<auto N>`(C++17+) | | **典型应用** | 泛型容器(如`std::vector<T>`) | 固定尺寸结构(如`std::array<T, N>`)| --- ### **2. 核心差异详解** #### **① 参数本质** | 类型参数 | 类型参数 | |---------|------------| | ```cpp template<typename T> class Box { T content; // T可以是任意类型 }; ``` | ```cpp template<int Size> class Buffer { char data[Size]; // Size必须是编译期常量 }; ``` | #### **② 代码生成机制** | 类型参数 | 类型参数 | |---------|------------| | 每个不同的**类型**生成独立实例<br>(`Box<int>`和`Box<float>`是不同类) | 每个不同的**数值**生成独立实例<br>(`Buffer<10>`和`Buffer<20>`是不同类) | #### **③ 使用限制** | 类型参数 | 类型参数 | |---------|------------| | 可接受任何合法类型(包括用户自定义类型) | 仅允许特定类型:整数、枚举、指针、引用(C++20起支持浮点型和字面量类类型) | | ```cpp template<typename T> void print(T val); // 接受任意类型参数 ``` | ```cpp template<size_t N> struct Array { // N必须是编译期常量表达式 }; ``` | --- ### **3. 典型应用场景** #### **类型模板参数** ```cpp // 通用容器 template<typename T> class Stack { std::vector<T> elements; public: void push(const T& value); T pop(); }; // 类型安全接口 template<typename Input, typename Output> Output convert(const Input& value); ``` #### **类型模板参数** ```cpp // 固定大小数组(尺寸编译期确定) template<typename T, size_t N> class StaticArray { T data[N]; }; // 编译期计算(模板元编程) template<int N> struct Factorial { static const int value = N * Factorial<N-1>::value; }; template<> struct Factorial<0> { value = 1; }; // 循环展开优化 template<int UnrollCount> void process() { // 编译器生成UnrollCount次展开的代码 } ``` --- ### **4. 代码示例对比** #### **类型参数示例** ```cpp template<typename T> T add(T a, T b) { return a + b; } // 使用: add<int>(3, 5); // 返回8 add<double>(2.5, 3.7); // 返回6.2 ``` #### **类型参数示例** ```cpp template<size_t N> void printNTimes(const std::string& msg) { for (size_t i = 0; i < N; ++i) std::cout << msg << "\n"; } // 使用: printNTimes<3>("Hello"); // 打印3次Hello ``` --- ### **5. 混合使用示例** ```cpp template<typename T, size_t Capacity> class FixedVector { T data[Capacity]; size_t size = 0; public: void push_back(const T& value) { if (size < Capacity) data[size++] = value; } }; // 使用: FixedVector<double, 100> measurements; // 存储最多100个double ``` --- ### **6. 选择指南** | **使用类型模板参数当** | **使用类型模板参数当** | |--------------------------------------|----------------------------------------| | 需要操作**不同类型的数据** | 需要固定**编译期已知的数值** | | 实现通用算法(如排序、查找) | 定义资源约束(如数组长度、矩阵维度) | | 构建类型无关的接口 | 进行模板元编程或编译期计算 | | 需要支持用户自定义类型 | 优化性能(如循环展开、内存布局控制) | --- ### **7. 高级特性** #### **类型参数** - 支持模板模板参数: ```cpp template<template<typename> typename Container> class Adapter { Container<int> storage; // 使用传入的容器类型 }; ``` #### **类型参数** - C++20支持类类型作为类型参数(需满足`constexpr`构造等条件): ```cpp struct Point { int x, y; }; template<Point P> class Widget { /* 使用P.x和P.y */ }; ``` --- ### **总结** - **类型模板参数**:实现**数据类型抽象**,构建通用组件 - **类型模板参数**:实现**数值参数化**,优化编译期行为 - 实际开发中常**组合使用**两者,例如`std::array<T, N>`同时指定元素类型和数组长度
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员乐逍遥

如果你觉得帮助了你,支持一下!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值