C++ 编译时检查微 Controller 引脚是否已从其他源文件初始化

标签 c++ templates embedded c++14 metaprogramming

通常,微 Controller 引脚可以用端口号和引脚号来标识。两者都是编译时间常数。 一个引脚可以有多个功能,如果在一个大项目中使用多个源文件可以初始化相同的引脚和中断在其他模块中实现的功能。

我想实现一个最初为空的编译时间列表,每次初始化一个引脚时,它都会检查该引脚是否已经存在 存在于该列表中,如果它存在,它将给出一个静态断言,否则它将在列表中插入引脚信息。运行时不需要列表。

我没有足够的元编程知识,如果有人能给我提供实现它的方向就太好了。如果已经有一些用于这种目的的库,请提供链接

最佳答案

你想要的是不可能的。 C++ 元编程没有状态,它更像是一种函数式语言而不是声明式语言。所以你不能有一个可变列表。唯一的状态可以通过创建新类型来引入,但是没有可用的语法来检查是否声明或定义了特定的非嵌套名称。

多个源文件(编译单元)是独立编译的,所以肯定没有“全局状态”,这使得它更不可能。

另外请注意,您所做的本质上是运行时的。编译器没有工具来检查您是否两次调用初始化函数。这些调用可能隐藏在某些运行时 if-else 决策的背后。而简单的写HAL_GPIO_Init();无论在整个程序中写多少次都不会报错。

我能想到的最简单的事情就是创建一个负责与引脚通信的 C++ 单例类。如果启用,您可以使用 error_codes 或异常来使用专用的 int init_GPIO 方法。您将不得不依赖于测试,而不是 static_assert - 单例工作正常并且 init_GPIO 的返回值不会被忽略。

如果你真的不想打扰单例,这个函数模板也可以:

template<std::size_t GPIO, std::size_t port> int GPIO_init(GPIO_InitStruct& s){
    static bool initialized=false;
    if(initialized) return <already_called>;
    initialized=true;
    //Assuming that you want to propagate the return value.
    return HAL_GPIO_Init(GPIO, port, s);// Replace with the correct call.
}

如果你需要线程安全的初始化,那么使用:

template<std::size_t GPIO, std::size_t port> int GPIO_init(GPIO_InitStruct& s){
    static std::once_flag initialized;
    int ret_val = <already_called>;
    auto call = [&](){ret_val = HAL_GPIO_Init(GPIO, port, s)};
    std::call_once(initialized, call);
    return ret_val;
}

关于C++ 编译时检查微 Controller 引脚是否已从其他源文件初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56801581/

相关文章:

c++ - 如何只检测一次相同的键盘按键

php - 使用 PHP 模板输出带有数据库值的网页(变量 URL)

c++ - 在模板函数上的 try/catch block 后返回

c - 如何在没有竞争条件的情况下将两个 32 位计数器读取为 64 位整数

node.js - 嵌入式系统是否支持redis缓存

C++:将零写入 .bmp 文件

c++ - enable_shared_from_this : Sharing the use count in member

c++ - 本地静态对象的非延迟初始化?

c++ - 为什么无法在可变参数模板中将尾随模板参数指定为默认值?

c - 由 main() 修改并由 ISR() 访问的全局变量