如何在自定义模板Array类中定义数组大小?
如何用现代C++规范约束数组容量模板参数并初始化固定大小数组?
一、规范约束模板参数的类型与值
你需要将第二个模板参数从类型参数改为非类型模板参数(用来指定数组大小的具体数值),并通过C++20的Concept约束其类型为无符号整数类型,避免绑定到特定的unsigned long。
1. 使用标准Concept约束类型
直接用C++20标准库的std::unsigned_integral概念,约束非类型模板参数的类型为任意无符号整数类型(如unsigned int、uint16_t、unsigned long等):
#include <concepts> export namespace zero::collections { // 约束Size为无符号整数类型的编译期常量 template <typename T, std::unsigned_integral auto Size> class Array { private: // 用原生固定大小数组存储元素,值初始化避免未定义行为 T m_data[Size]{}; public: // 获取数组大小的常量表达式 constexpr auto size() const noexcept { return Size; } // 元素访问运算符 constexpr T& operator[](std::size_t index) { return m_data[index]; } constexpr const T& operator[](std::size_t index) const { return m_data[index]; } }; }
2. 自定义Concept添加更严格的约束(可选)
如果需要确保数组大小为正自然数(即Size > 0),可以自定义Concept:
#include <concepts> // 自定义Concept:无符号整数且值大于0 template <auto N> concept PositiveUnsignedNatural = std::unsigned_integral<decltype(N)> && (N > 0); export namespace zero::collections { // 使用自定义Concept约束Size template <typename T, PositiveUnsignedNatural Size> class Array { private: T m_data[Size]{}; public: constexpr auto size() const noexcept { return Size; } constexpr T& operator[](std::size_t index) { return m_data[index]; } constexpr const T& operator[](std::size_t index) const { return m_data[index]; } }; }
二、正确初始化固定大小数组
原代码中的T array[]是柔性数组成员,仅适用于运行时动态扩展的场景,不符合编译期固定大小数组的需求。推荐两种实现方式:
1. 原生固定大小数组
用T m_data[Size]{};定义成员,其中{}会对数组元素进行值初始化:
- 内置类型(如
int、double)会被初始化为0 - 自定义类型会调用默认构造函数
2. 封装std::array(推荐)
用标准库的std::array作为成员,它提供了更安全的接口(如边界检查的at()方法),且行为更一致:
#include <concepts> #include <array> export namespace zero::collections { template <typename T, std::unsigned_integral auto Size> class Array { private: std::array<T, Size> m_data{}; public: constexpr auto size() const noexcept { return m_data.size(); } constexpr T& operator[](std::size_t index) { return m_data[index]; } constexpr const T& operator[](std::size_t index) const { return m_data[index]; } // 可选:暴露std::array的迭代器支持 constexpr auto begin() noexcept { return m_data.begin(); } constexpr auto end() noexcept { return m_data.end(); } }; }
三、使用示例
// 传入不同无符号整数类型的大小 zero::collections::Array<int, 10u> int_arr; // Size为unsigned int zero::collections::Array<double, 5UL> double_arr; // Size为unsigned long zero::collections::Array<char, static_cast<uint16_t>(20)> char_arr; // Size为uint16_t // 如果使用了PositiveUnsignedNatural约束,下面的代码会编译报错 // zero::collections::Array<int, 0u> invalid_arr; // 违反Size>0的约束
原代码问题说明
你原代码中的T array[]是柔性数组成员,存在以下限制:
- 必须是类的最后一个非静态成员
- 类必须是标准布局类型(不能有虚函数、虚基类)
- 无法存储编译期固定大小的元素,仅适用于运行时动态分配的场景,因此不适合你的需求。
内容的提问来源于stack exchange,提问作者Alex Vergara
相关产品推荐
相关产品推荐

