То, что вы хотите, не возможно. Метапрограммирование C ++ не имеет состояния , оно больше похоже на функциональный язык, чем на декларативный. Таким образом, вы не можете иметь изменяемый список. Единственное состояние может быть введено путем создания новых типов, но нет доступного синтаксиса, чтобы проверить, объявлено или определено конкретное не вложенное имя.
Несколько исходных файлов (модулей компиляции) компилируются независимо, поэтому, безусловно, нет «глобального состояния», и это делает его более невозможным.
Кроме того, обратите внимание, что то, что вы делаете, является неотъемлемой частью времени выполнения. У компилятора нет инструментов, позволяющих проверить, вызываете ли вы функцию инициализации дважды. Эти вызовы могут быть скрыты за некоторыми решениями if-else
времени выполнения. И просто написать HAL_GPIO_Init();
независимо от того, сколько раз во всей программе не ошибка.
Самая простая вещь, о которой я могу подумать, - это создание одноэлементного класса C ++, который отвечает за связь с выводами. Вы можете использовать выделенный метод 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;
}