/** * @author Matthew Kennedy, (c) 2019 * * This lets us compose multiple functions in to a single function. If we have * conversion functions F(x), G(x), and H(x), we can define a new function * FuncChain that will compute H(G(F(X))). F first, then G, then H. */ #pragma once #include "sensor_converter_func.h" #include #include namespace priv { template class FuncChain; template <> class FuncChain<> { protected: SensorResult convert(float input) const { // Base case is the identity function return input; } void showInfo(float testInputValue) const { // base case does nothing (void)testInputValue; } }; template class FuncChain : private FuncChain { static_assert(std::is_base_of_v, "Template parameters must inherit from SensorConverter"); private: using TBase = FuncChain; public: SensorResult convert(float input) const { // Convert the current step SensorResult currentStep = m_f.convert(input); // if it was valid, pass this result to the chain of (n-1) functions that remain if (currentStep.Valid) { return TBase::convert(currentStep.Value); } else { return unexpected; } } // Get the element in the current level template std::enable_if_t, TGet &> get() { return m_f; } // We don't have it - check level (n - 1) template std::enable_if_t, TGet &> get() { return TBase::template get(); } void showInfo(float testInputValue) const { // Print info about this level m_f.showInfo(testInputValue); // If valid, recurse down auto res = m_f.convert(testInputValue); if (res.Valid) { TBase::showInfo(res.Value); } } private: TFirst m_f; }; } // namespace priv template class FuncChain : public SensorConverter { public: // Perform chained conversion of all functions in TFuncs SensorResult convert(float input) const override { return m_fs.convert(input); } // Access the sub-function of type TGet template TGet &get() { return m_fs.template get(); } void showInfo(float testInputValue) const override { m_fs.showInfo(testInputValue); } private: priv::FuncChain m_fs; };