Enforcing Base class method implementations in derived classes using CRTP

1 day ago 1
ARTICLE AD BOX

I am trying to implement an Interface with deterministic behavior (no virtual is one of the requirements). The goal is to achieve what interface achieves i.e. the derived classes must implement the methods of the interface.

My Interface class looks like this.

template<typename Derived> struct DeviceInterface { void initialize() { static_cast<Derived*>(this)->initialize_impl(); } void shutdown() { static_cast<Derived*>(this)->shutdown_impl(); } };

My Derived class would look like.

class DeviceA : public DeviceInterface<DeviceA> { public: void initialize_impl() { std::cout << "DeviceA initialize\n"; } void shutdown_impl() { std::cout << "DeviceA shutdown\n"; } };

If I remove void shutdown_imp() {...} in the DeviceA it still compiles.

I want to enforce that all derived classes must implement initialize_impl() and shutdown_impl()

I can achieve this by adding below code in the DeviceInterface class

template<typename T> concept DeviceRequirements = requires(T t) { { t.initialize_impl() } -> std::same_as<void>; { t.shutdown_impl() } -> std::same_as<void>; }; template<typename Derived> struct DeviceInterface { ~DeviceInterface() { if constexpr (!DeviceRequirements<Derived>) { static_assert(DeviceRequirements<Derived>, "Derived must implement initialize_impl() and shutdown_impl()"); } } };

I have static_assert in the destructor that enforces the rule and I get a very clear compilation error as shown below:

error C2338: static_assert failed: 'Derived must implement initialize_impl() and shutdown_impl()'

If I try the static_assert in the constructor, i get all sort of confusing compiler messages without anything meaningful in the error (mostly related to incomplete derived class).

Is this approach a good design? Or there are better ways (and used in production code) to achieve this?

Read Entire Article