C++如何实现向同一FIFO类构造函数传入不同自定义struct
错误原因说明
- 第一个报错:
std::array的第二个模板参数要求是编译期可确定的常量,你把运行时传入的depth作为参数,编译器无法在编译阶段确定大小,因此报错。 - 第二个报错:
struct1是类型名称,不是可传递的变量/值,普通构造函数只能接收值参数,不能直接接收类型作为入参。
解决方案
你需要用C++类模板实现FIFO,模板可以接收元素类型、队列深度作为模板参数,完全满足你不同实例用不同结构体、FIFO不感知具体结构的需求。
嵌入式场景优先用静态内存分配的实现,避免堆内存碎片化,代码如下:
#include <array> #include <cstdint> // C++17及以上支持std::optional,嵌入式编译器一般都兼容,返回空可选值表示队列空/满 #include <optional> template<typename T, uint32_t DEPTH> class FIFO { private: std::array<T, DEPTH> buffer; uint32_t head = 0; uint32_t tail = 0; uint32_t count = 0; public: FIFO() = default; // 入队,成功返回true,队列满返回false bool enqueue(const T& item) { if (isFull()) return false; buffer[tail] = item; tail = (tail + 1) % DEPTH; count++; return true; } // 出队,队列空返回std::nullopt,否则返回元素 std::optional<T> dequeue() { if (isEmpty()) return std::nullopt; T item = buffer[head]; head = (head + 1) % DEPTH; count--; return item; } bool isFull() const { return count == DEPTH; } bool isEmpty() const { return count == 0; } uint32_t size() const { return count; } uint32_t capacity() const { return DEPTH; } }; // 自定义结构体 struct struct1 { double s1Var1; uint32_t s1Var2; }; struct struct2 { bool s2Var1; };
实例化方式:
// 元素为struct1,深度16的FIFO FIFO<struct1, 16> fifo1; // 元素为struct2,深度8的FIFO FIFO<struct2, 8> fifo2;
如果你的嵌入式环境不支持C++17的std::optional,可以把出队接口改成返回bool,参数用引用接收出队元素:
bool dequeue(T& out_item) { if (isEmpty()) return false; out_item = buffer[head]; head = (head + 1) % DEPTH; count--; return true; }
调用方式:
struct1 item; if(fifo1.dequeue(item)) { // 出队成功,处理item }
嵌入式场景适配优化建议
- 中断/DMA操作场景下,入队出队操作需要加临界区保护,比如操作前关对应外设的中断,操作完成后再开,避免队列计数、指针出现并发错误。
- 如果需要运行时动态指定队列深度,可以把模板实现改成普通类,内部用
std::vector<T>作为缓存,构造函数传入深度参数初始化vector大小即可,注意只有嵌入式环境允许用堆内存时才可以这么做。
需补充学习的知识点
- C++类模板的基本使用,模板类型参数、非类型参数的区别
- 嵌入式C++静态内存、动态内存的适用场景和注意事项
- 中断安全队列的实现逻辑
设计思路评价
你当前的分层设计非常合理,UART驱动只负责队列的读写操作,不感知上层业务结构体的定义,完全符合单一职责原则,方便后续新增外设时不需要修改底层UART驱动代码,可扩展性很好。
内容的提问来源于stack exchange,提问作者Gene
相关产品推荐
相关产品推荐

