模板参数与构造函数参数的区别及适用场景
两种模板结构体大小指定方式的区别与适用场景
两种实现方式
方式一:构造函数传递参数
template <typename T> struct Foo { int m_size; Foo(int u_size) : m_size {u_size} { } };
方式二:非类型模板参数(类似std::array实现)
template <typename T, int u_size> struct Foo { int m_size; Foo() : m_size {u_size} { } };
核心区别
- 大小确定时机:
- 方式一的
m_size是运行时确定的,构造对象时传入的参数决定大小,同一模板实例(比如Foo<int>)的不同对象可以有不同的m_size值。 - 方式二的
u_size是编译时确定的,模板实例化时必须指定常量值,每个不同的u_size会生成独立的模板类型(比如Foo<int, 5>和Foo<int, 10>是完全不同的类型)。
- 方式一的
- 内存与性能:
- 方式一中
m_size是结构体成员变量,每个对象都会额外存储这个整数,占用运行时内存。 - 方式二中
u_size是编译期常量,不需要在对象中存储,结构体内存占用更小;编译器还能基于这个常量做更多优化(比如循环展开、静态数组大小确定等)。
- 方式一中
- 类型一致性:
- 方式一的同一模板实例下所有对象属于同一类型,比如
Foo<int> a(5)和Foo<int> b(10)类型完全相同,可以互相赋值、放在同一个容器里。 - 方式二中不同
u_size对应不同类型,Foo<int,5>和Foo<int,10>无法互相赋值,也不能直接放在同一个容器中(除非用变体或基类指针)。
- 方式一的同一模板实例下所有对象属于同一类型,比如
- 灵活性:
- 方式一支持动态大小,运行时可以根据变量、用户输入等调整大小,灵活性更高。
- 方式二只能使用编译期常量(字面量、
constexpr变量),无法在运行时修改大小。
适用场景
方式一适用场景
- 需要动态调整大小的场景:比如结构体大小要根据运行时数据(用户输入、文件内容)决定。
- 希望同一模板类型的对象可以统一处理的场景:比如要把不同大小的对象放进同一个
std::vector,或者需要统一接口进行赋值、传递。 - 对运行时性能要求不高,更看重灵活性的场景:比如小型工具类,大小变化频繁且不需要编译期优化。
方式二适用场景
- 需要编译期确定大小,依赖常量做优化的场景:比如实现固定大小容器(类似
std::array),编译器可以对数组操作做极致优化,减少运行时开销。 - 要求类型安全,不同大小视为不同类型的场景:通过类型系统避免不同大小的对象被错误赋值。
- 内存敏感的场景:不需要额外存储大小变量,节省每个对象的内存,适合大量创建对象的场景。
内容的提问来源于stack exchange,提问作者dnl
相关产品推荐
相关产品推荐

