Предлагаю еще раз вернуться к сути - на прикладном уровне не должно
быть манипуляции битами. Если нужно открыть шлагбаум, должно быть:
barrier_open()
А не манипуляция битами, обернутая в классы и шаблоны.
Тогда внутри barrier_open промежуточный объектный слой (в 90% случаев) уже не нужен.
Там уже и так речь о битах в регистрах.
Если там "все сильно сложнее", то ладно, пусть будут объекты.
Принципиальный вопрос где и как проводить границу прикладного кода.
Важно, ни в коем случае не:
barrier.open();
Потому что это уже объект в прикладном коде и он должен оперировать ТОЛЬКО понятиями прикладного кода.
Никаких something.set_bit() в прикладном коде быть не должно.
Как приемлемый вариант:
barrier::open(){
bsp.barrier_open_cmd(self.hw_addr);
self.state = barrier_state_wait_to_open;
self.timer.reset();
}