103 lines
3.8 KiB
C
103 lines
3.8 KiB
C
|
// 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
|