zoukankan      html  css  js  c++  java
  • C++模板元编程

    C++真是一门自由的语言,虽然糖没有C#那么多,但是你想要怎么写,想要实现什么,想要用某种编程范式或者语言特性,它都会提供。

    开大数运算类的新坑的时候(又是坑),无意中需要解决一个需求:大数类需要分别实现接受整数和浮点数的构造函数,构造函数中初始化类内保存数据的容器,所有整数的构造方法相同,所有浮点数的构造方法也相同,现在的目标是,找到一个机制,能尽可能少的实现代码,争取做到所有整数实现一份构造函数,所有浮点数实现一份构造函数。

    学过C++的你一定会想到模板,这里有了

    template<typename T>
    Number(T num)
        : _num(ToVectorBool(num))
    {}

    这里我用了vector<bool>来储存一个大数的二进制位模式,ToVectorBool是将数字转换为vector<bool>

    但是现在的模板还没有Concept,如何来限制ToVectorBool接受的模板参数只能是整数和浮点数呢?你可能想到用模板的特例化,各种浮点数的实现成为特例,而剩下的整数使用非特例的实现,然后用static_assert来限定非特例实现中不是整数类型的T。

    然而不要忘了,特例化的函数是要每个特例写一份代码的,这样多不优雅啊。同样是利用函数重载决议,我们需要一个筛选器,判断类型参数T是整数还是浮点数还是什么都不是。

    这样我们就回到了模板元编程的范围,我们需要写一个MultiState模板结构,它接受一个T,和用来接受这个类型T并返回结果的模板结构,用我在模板元编程代码中的约定,就是接受TStatement和TPreds...,依次判断TStatement是否符合TPreds...里每个谓词,返回判断的结果:在第几个谓词哪里得到了TrueType。

    我们还需要typedef出State<N>,正好我以前写过Int<N>模板整数类型,就用它了

    本着用户不乱用的原则,MultiState本身不能把参数N暴露给用户,于是套了一层MultiStateImpl,用MultiState去“调用”MultiStateImpl

    为了可扩展性,这里使用了变长模板参数包,做了一个template<class T> class... TPreds,这样可以用模板参数包的一些技巧,做出接受任意个谓词的MultiState

    template<int N>
    using State = Int<N>;
    
    template<int N, class TStatement, template<class T> class TPred, template<class T> class... TPreds>
    struct MultiStateImpl
    {
        using Result = typename If<
            typename TPred<TStatement>::Result,
            State<N>,
            typename MultiStateImpl<
                N + 1,
                TStatement,
                TPreds...
            >::Result
        >::Result;
    };
    
    template<int N, class TStatement>
    struct MultiStateImpl
    {
        using Result = FalseType;
    };
    
    template<class TStatement, template<class T> class... TPreds>
    struct MultiState
    {
        using Result = typename MultiStateImpl<0, TStatement, TPreds...>::Result;
    };

    可以看到,代码里首先检查TPred<TStatement>::Result,如果正确,直接返回State<N>,否则,返回下一层MultiState<N+1,TStatement, TPreds...>的结果,如果都不成立,到了MultiState<N, TStatement>的实现,就直接返回FalseType,表示哪个都不满足。

    爽啊,用起来就是这样的

    template<typename TNumber>
    Number::Number(TNumber& number)
        : _num(ToVectorBool(number, MultiState<TNumber, IsInteger, IsFloat>::Result()))
    {
    }
    
    template<typename TInteger>
    static std::vector<bool> Number::ToVectorBool(TInteger& intNumber, State<1>)
    {
        //Integer 实现略
    }
    
    template<typename TFloat>
    static std::vector<bool> Number::ToVectorBool(TFloat& floatNumber, State<2>)
    {
        //Float 实现略
    }
    
    template<typename TOther>
    static std::vector<bool> Number::ToVectorBool(TOther& other, FalseType)
    {
        static_assert(0, "Not a number.");
    }

    还可以改,把State也做成模板参数包,State<1>这样的写法还不优雅

    感觉怪怪的,不过好有意思

  • 相关阅读:
    积水路面Wet Road Materials 2.3
    门控时钟问题
    饮料机问题
    Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)
    Educational Codeforces Round 82 (Rated for Div. 2)部分题解
    Educational Codeforces Round 86 (Rated for Div. 2)部分题解
    Grakn Forces 2020部分题解
    2020 年百度之星·程序设计大赛
    POJ Nearest Common Ancestors (RMQ+树上dfs序求LCA)
    算法竞赛进阶指南 聚会 (LCA)
  • 原文地址:https://www.cnblogs.com/pointer-smq/p/4963365.html
Copyright © 2011-2022 走看看