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>这样的写法还不优雅

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

  • 相关阅读:
    CSS笔记
    EasyUI笔记
    EasyUI treegrid 获取编辑状态中某字段的值 [getEditor方法获取不到editor]
    2019.10.12解题报告
    %lld 和 %I64d
    关于kmp算法
    洛谷p2370yyy2015c01的U盘题解
    About me & 友链
    关于Tarjan
    洛谷p3398仓鼠找suger题解
  • 原文地址:https://www.cnblogs.com/pointer-smq/p/4963365.html
Copyright © 2011-2022 走看看