C++模板元编程 记录

常犯的小错误:

  1. 没有std::is_same_t,只有std::is_same_v
  2. 在模板类定义value时记得加typenameusing value = typename ...

Policy定义:

struct AccPolicy
{
    struct AccuTypeCate
    {
        struct Add;
        struct Mul;
    };
    using Accu = AccuTypeCate::Add;

    struct IsAveValueCate;
    static constexpr bool IsAve = false;

    struct ValueTypeCate;
    using Value = float;

    using MajorClass = AccPolicy;
};

这里每一个struct都起到命名空间的作用,用于容纳一系列类型(类型即配置)。
MajorClassMinorClass这两个名字将贯穿所有代码,这是一种约定:MajorClass表示了用于一个用途的配置,MinorClass表示该用途下对某个方面的细分配置。
如果我们接受这套约定,下面的元函数代码就有通用性了。

类型容器:

template <typename... TPolicies>
struct PolicyContainer;

MajorFilter_元函数过滤类型容器中的类型,使得它们有相同的MajorClass。这里写得复杂了点,可以不需要Filter_

template <typename TCurPolicy, bool insert, typename... Filtered>
struct Filter_
{
    using value = typename PolicyContainer<Filtered...>;
};

template <typename TCurPolicy, typename... Filtered>
struct Filter_<TCurPolicy, true, Filtered...>
{
    using value = typename PolicyContainer<Filtered..., TCurPolicy>;
};

template <typename TPolicyContainer, typename TMajorClass, typename... TPolicies>
struct MajorFilter_
{
    using type = typename TPolicyContainer;
};

template <typename... Filtered, typename TMajorClass, typename TCurPolicy, typename... TPolicies>
struct MajorFilter_<PolicyContainer<Filtered...>, TMajorClass, TCurPolicy, TPolicies...>
{
    constexpr static bool insert = std::is_same_v<TMajorClass, typename TCurPolicy::MajorClass>;
    using type = typename MajorFilter_<typename Filter_<TCurPolicy, insert, Filtered...>::value, TMajorClass, TPolicies...>::type;
};

&运算符的元函数版本:

/* and的元函数版本 */
template <bool T, bool P>
constexpr bool AndValue = P;

template <bool P>
constexpr bool AndValue<false, P> = false;

传入MinorClass和一个类型列表,检查列表的MinorClass是否和给定的MinorClass都不同:

template <typename TMinorClass, typename... TP>
struct MinorDedup_
{
    static constexpr bool value = true;
};

template <typename TMinorClass, typename TCurPolicy, typename... TP>
struct MinorDedup_<TMinorClass, TCurPolicy, TP...>
{
    using TCurMirror = typename TCurPolicy::MinorClass;
    constexpr static bool cur_check = !std::is_same_v<TMinorClass, TCurMirror>;
    constexpr static bool value = AndValue<cur_check, MinorDedup_<TMinorClass, TP...>::value>;
};

传入Policy列表,检查MinorClass是否互不相同:

template <typename TPolicyCont>
struct MinorCheck_
{
    static constexpr bool value = true;
};

template <typename TCurPolicy, typename... TP>
struct MinorCheck_<PolicyContainer<TCurPolicy, TP...>>
{
    static constexpr bool cur_check = MinorDedup_<typename TCurPolicy::MinorClass, TP...>::value;
    static constexpr bool value = AndValue<cur_check, MinorCheck_<PolicyContainer<TP...>>::value>;
};

传入PolicyContainer,判断容器内是否有元素:

template <typename T>
constexpr bool IsArrayEmpty = false;

template <typename... TPolicy>
constexpr bool IsArrayEmpty<PolicyContainer<TPolicy...>> = sizeof...(TPolicy) == 0;

定义Policy:

template <typename TPolicyCont>
struct PolicySelRes;

template <typename TPolicy>
struct PolicySelRes<PolicyContainer<TPolicy>> : public TPolicy
{
};

template <typename TCurPolicy, typename... TOtherPolicies>
struct PolicySelRes<PolicyContainer<TCurPolicy, TOtherPolicies...>>
    : public TCurPolicy, public PolicySelRes<PolicyContainer<TOtherPolicies...>>
{
};

组合Policy,构造包含多个配置的Policy

template <typename TMajorClass, typename TPolicyContainer>
struct Selector_;

template <typename TMajorClass, typename... TPolicies>
struct Selector_<TMajorClass, PolicyContainer<TPolicies...>>
{
    using TMF = typename MajorFilter_<PolicyContainer<>,
                                      TMajorClass,
                                      TPolicies...>::type;

    static_assert(MinorCheck_<TMF>::value, "Minor class set conflict!");

    using type = typename std::conditional_t<IsArrayEmpty<TMF>,
                                             TMajorClass,
                                             PolicySelRes<TMF>>;
};

template <typename TMajorClass, typename TPolicyContainer>
using PolicySelect = typename Selector_<TMajorClass, TPolicyContainer>::type;

只是返回false的模板:

template <typename T>
constexpr bool DependencyFalse = false;

主体函数:

template <typename... TPolicies>
struct Accumulator
{
    using TPoliCont = PolicyContainer<TPolicies...>;
    using TPolicyRes = PolicySelect<AccPolicy, TPoliCont>;

    using ValueType = typename TPolicyRes::Value;
    static constexpr bool is_ave = TPolicyRes::IsAve;
    using AccuType = typename TPolicyRes::Accu;

public:
    template <typename TIn>
    static auto Eval(const TIn &in)
    {
        if constexpr (std::is_same<AccuType, AccPolicy::AccuTypeCate::Add>::value)
        {
            ValueType count = 0;
            ValueType res = 0;
            for (const auto &x : in)
            {
                res += x;
                count += 1;
            }

            if constexpr (is_ave)
                return res / count;
            else
                return res;
        }
        else if constexpr (std::is_same<AccuType, AccPolicy::AccuTypeCate::Mul>::value)
        {
            ValueType res = 1;
            ValueType count = 0;
            for (const auto &x : in)
            {
                res *= x;
                count += 1;
            }
            if constexpr (is_ave)
                return pow(res, 1.0 / count);
            else
                return res;
        }
        else
        {
            static_assert(DependencyFalse<AccuType>);
        }
    }
};

Policy定义(我不喜欢宏定义)

struct PMulAccu : virtual public AccPolicy
{
    using MinorClass = AccPolicy::AccuTypeCate;
    using Accu = AccPolicy::AccuTypeCate::Mul;
};

struct PAddAccu : virtual public AccPolicy
{
    using MinorClass = AccPolicy::AccuTypeCate;
    using Accu = AccPolicy::AccuTypeCate::Add;
};

struct PAve : virtual public AccPolicy
{
    using MinorClass = AccPolicy::IsAveValueCate;
    static constexpr bool IsAve = true;
};

struct PNoAve : virtual public AccPolicy
{
    using MinorClass = AccPolicy::IsAveValueCate;
    static constexpr bool IsAve = false;
};

template <typename T>
struct PValueTypeIs : virtual public AccPolicy
{
    using MinorClass = AccPolicy::ValueTypeCate;
    using Value = T;
};
posted @ 2024-11-09 23:31  爱尔奎特你带我走吧  阅读(16)  评论(0)    收藏  举报