tmp-policy/accumulator.h

103 lines
3.8 KiB
C
Raw Permalink Normal View History

2022-08-04 17:13:06 +08:00
// 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 <type_traits>
#include <cmath>
#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 <typename T>
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 <typename ... TPolicies>
class Accumulator
{
// Put all the policy objects into a PolicyContainer.
using PolicyCont = PolicyContainer<TPolicies...>;
// Use PolicySelect Meta-Function to get the policy selection result.
using PSR = PolicySelect<PolicyCont, AccPolicy>;
// 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 <typename TInput>
static auto eval(const TInput& in)
{
ResultType res{};
int count{};
// If we want to perform "add" ...
if constexpr (std::is_same<AccPolicy::AccuTypeCate::Add, AccuType>::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<ResultType>(count);
else
// ... if not, simply returns the sum.
return res;
}
// Or if we want to perform "multiply" ...
else if constexpr (std::is_same<AccPolicy::AccuTypeCate::Mul, AccuType>::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<ResultType>(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<AccuType>, "Invalid policy argument!");
}
}
};
#endif //TMP_POLICY_ACCUMULATOR_H