// tmp_policy // Created by lucas on 22-8-4. // Re-implementation of a typical policy architecture in C++ Template Meta-Programming. #ifndef TMP_POLICY_ACCUMULATOR_H #define TMP_POLICY_ACCUMULATOR_H // A demo for integrating the policy architecture // into your project. #include #include #include "accpolicy.h" #include "policy_fundamentals.h" // According to the C++ Standard, // Direct use of static_assert(false) results in undefined behavior, // so we define a type-dependent boolean variable whose value is false. template constexpr bool DependencyFalse = false; /** * @brief class Accumulator - the class performs "accumulation" * and it's behavior is controlled by policy objects. * @tparam TPolicies The policy objects which control the class's behavior. */ template class Accumulator { // Put all the policy objects into a PolicyContainer. using PolicyCont = PolicyContainer; // Use PolicySelect Meta-Function to get the policy selection result. using PSR = PolicySelect; // According to the policy selection result, // we get the necessary information to control the Accumulator's behavior. // AccuType - controls how the "accumulation" works; Add or Multiply? using AccuType = typename PSR::AccuType; // IsAve - returns the average or the original result? static constexpr bool IsAve = PSR::IsAveValue; // ResultType - What type do you expect the Accumulator to return? using ResultType = typename PSR::ResultType; public: /** * @brief eval - The function which does the "accumulation". * @tparam TInput The type of parameter in - it will be judged by the compiler. * @param in The input array which contains the elements waiting to be accumulated. * It needs to support range-based for statement. * @return The "accumulation" result. User-specified. */ template static auto eval(const TInput& in) { ResultType res{}; int count{}; // If we want to perform "add" ... if constexpr (std::is_same::value) { // Add the all elements to res ... for (const auto& element: in) { res += element; // ... and also records the number of elements. count += 1; } // If we want to calculate average... if constexpr (IsAve) // ... calculates the average and returns. return res / static_cast(count); else // ... if not, simply returns the sum. return res; } // Or if we want to perform "multiply" ... else if constexpr (std::is_same::value) { // Because 0 times any number equals 0 ... // ... we need to give res an initial value. res = 1; // Multiply the all elements to res ... for (const auto& element: in) { res *= element; // ... and also records the number of elements. count += 1; } // If we want to calculate average... if constexpr (IsAve) // ... calculates the average and returns. return std::pow(res, 1.0 / static_cast(count)); else // ... if not, simply returns the sum. return res; } else { // We have triggered logic that should not be triggered ... // ... the solution is to generate a compile error. static_assert(DependencyFalse, "Invalid policy argument!"); } } }; #endif //TMP_POLICY_ACCUMULATOR_H