#include <cstdint>
#include <cstdio>
// Timebase A: SysTick (1 kHz)
struct SysTickTimer {
static std::uint32_t ticks() {
return 100;
}
static std::uint32_t freq_hz() {
return 1000;
}
};
// Timebase B: RTC (32 Hz)
struct RtcTimer {
static std::uint32_t ticks() {
return 4;
}
static std::uint32_t freq_hz() {
return 32;
}
};
template<typename Timer>
class Scheduler {
public:
std::uint32_t elapsed_ms() const {
return (Timer::ticks() * 1000U) / Timer::freq_hz();
}
};
// Compile-time timebase selection
using SelectedTimer = SysTickTimer;
// using SelectedTimer = RtcTimer;
int main() {
Scheduler<SelectedTimer> scheduler;
std::printf("elapsed_ms=%u\n",
static_cast<unsigned>(scheduler.elapsed_ms()));
return 0;
}
Explanation & Logic Summary:
The template code fails to compile because no timebase type is provided.
This is intentional: the firmware must not exist without a build-time decision.
The Scheduler class requires a timebase type as a template parameter.
Providing Scheduler<SysTickTimer> binds the timebase at compile time.
No runtime state, flags, or branches exist.
The compiler can fully inline all calls and eliminate unused code.
Firmware Relevance & Real-World Context:
In real embedded systems:
Using compile-time polymorphism:
This problem demonstrates compile-time polymorphism as a build-time safety mechanism, not just a performance optimization.
Input
Expected Output
elapsed_ms=100