diff --git a/src/modules/submodules/base_step.hpp b/src/modules/submodules/base_step.hpp new file mode 100644 index 00000000..0b0ac868 --- /dev/null +++ b/src/modules/submodules/base_step.hpp @@ -0,0 +1,72 @@ +// +// Canadian Hydrological Model - The Canadian Hydrological Model (CHM) is a novel +// modular unstructured mesh based approach for hydrological modelling +// Copyright (C) 2018 Christopher Marsh +// +// This file is part of Canadian Hydrological Model. +// +// Canadian Hydrological Model is free software: you can redistribute it and/or +// modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Canadian Hydrological Model is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Canadian Hydrological Model. If not, see +// . +// + +// +// Created by Donovan Allum 2025 +// + +#pragma once +#include + +/** + * @brief Base class for submodules using the Curiously Recurring Template Pattern (CRTP). + * + * This class enforces that derived classes implement an `execute_impl(Data&) const` method, + * and provides a public `execute(Data&) const` method that forwards to the derived implementation. + * + * The CRTP pattern allows compile-time polymorphism, enabling static dispatch and + * avoiding the overhead of virtual functions. This is useful for performance-critical + * code or when templates are preferred over inheritance. + * + * Usage example: + * @code + * struct MyStep : public base_step { + * void execute_impl(MyData& d) { + * // Step-specific logic here + * } + * }; + * MyStep step; + * MyData data; + * step.execute(data); // Calls MyStep::execute_impl(data) + * @endcode + */ + +template +concept GuaranteeImplementExecute = requires(const T& t, Data& d) { + { t.execute_impl(d) } -> std::same_as; +}; + +template +class base_step { +protected: + base_step() {}; +public: + void execute(Data& d) const { + + static_assert(GuaranteeImplementExecute, + "Derived class must implement: void execute_impl(Data&) const"); + + static_cast(this)->execute_impl(d); + } + ~base_step() {}; +};