121. Mandatory Build-Time Timebase Selection

#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:

  • Timebases are selected per board or product variant
  • Runtime switching of clock sources is unsafe
  • Deterministic scheduling is critical

Using compile-time polymorphism:

  • Prevents invalid firmware builds
  • Eliminates runtime overhead
  • Encodes hardware assumptions directly into the type system

This problem demonstrates compile-time polymorphism as a build-time safety mechanism, not just a performance optimization.

 

 

 

Loading...

Input

Expected Output

elapsed_ms=100