• 编译期的序列遍历


    背景

    函数参数可变长

    举例子最多的就是print, 因为你不知道使用者要print几个参数,但是当使用者一旦在使用这个函数时使用参数个数就是确定的,对于开发人员的的话,你总不能写0-N个参数的函数吧? 下面这种需要写N个参数,所以不现实。

    template<typename T1>
    print(T1 arg_1)
    {
    	cout<<arg_1;
    }
    template<typename T1, typename T2, ....typename Tn>
    print(T1 arg_1, T2 arg_2, .., Tn arg_n)
    {
    	cout<<arg_1;
    	cout<<arg_2;
    	...
    	cout<<arg_n;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    为此编译器提供了下面的方式, 在C++11的时候,如果使用可变参数的话一定是需要递归(很重要,不管函数模板还是类处理变长都需要),因为参数包args单个函数里面拆不开。

    // 当可变参数包为0的时候走到这个分支
    template<typename T1>
    print(T1 arg_1)
    {
    	cout<<arg_1<<endl;
    };
    
    template<typename T1, typename... Types>
    print(T1 arg_1, Types... args)
    {
    	cout<<arg_1<<endl;
    	print(args...);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里需要补充一个模板推导的小知识:

    #include 
    using namespace std;
    
    template<int... Index>
    struct IndexSquence
    {
    };
    
    template<typename T, int... Index>
    void test(T first, IndexSquence<Index...>)
    {
    };
    
    int main()
    {
      test(1, IndexSquence<2,3,4>() );
      return 0;
    }
    //下面是编译期的实例化结果,可以看到可以通过模板推导出来index的几个数值。
    #ifdef INSIGHTS_USE_TEMPLATE
    template<>
    void test<int, 2, 3, 4>(int first, IndexSquence<2, 3, 4>)
    {
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    拿这个数列干啥呢?比如对每个数字算平方,或者干啥都可以,这个知识要补充一下。

    类模板可变长

    同上

    代码

    下面的demo是根据上面的知识铺垫后的一个集成代码,标准是C++11, 需要好好研究研究,稍微解释一下实例化的顺序,当要生成一个IndexSequenceMaker的类的时候,需要要实例化一个子类,然后对N=0的情况给一个类的偏特化作为终止条件,设计的很巧妙,C++啥时候也学不完。

    #include 
    #include 
    
    
    template <size_t... S>
    struct IndexSequence {}; 
    
    template <size_t N, size_t... S>
    struct IndexSequenceMaker : public IndexSequenceMaker<N - 1, N - 1, S...> {}; 
    
    template <size_t... S>
    struct IndexSequenceMaker<0, S...> {
        using Type = IndexSequence<S...>;
    };
    
    template <size_t N>
    using MakeIndexSequence = typename IndexSequenceMaker<N>::Type;
    
    template <typename T, typename F>
    void ForEachTuple(T&& tuple, F&& consumer)
    {
        ForEachTupleInternal(std::forward<T>(tuple), std::forward<F>(consumer), MakeIndexSequence<std::tuple_size<T>::value> {});
    }
    
    template <typename T, typename F, size_t... S>
    void ForEachTupleInternal(T&& tuple, F&& consumer, IndexSequence<S...>)
    {
        std::initializer_list<int> { (consumer(std::get<S>(tuple)), 0)... };
    }
    
    struct Consumer {
        template <typename T>
        void operator()(T&& value)
        {   
            std::cout << value << std::endl;
        }   
    };
    
    int main(int argc, char* argv[])
    {
        ForEachTuple(std::make_tuple(1, 2.1, "Hello"), Consumer {});
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    下面是c++14支持了序列生成

    template <typename T, typename F>
    void ForEachTuple(T&& tuple, F&& consumer)
    {
        // c++ 14 的 make_index_sequence
        ForEachTupleInternal(std::forward<T>(tuple), std::forward<F>(consumer), std::make_index_sequence<std::tuple_size<T>::value> {});
    }
    
    template <typename T, typename F, size_t... S>
    void ForEachTupleInternal(T&& tuple, F&& consumer, std::index_sequence<S...>)
    {
        std::initializer_list<int> { (consumer(std::get<S>(tuple)), 0)... };
    }
    
    int main(int argc, char* argv[])
    {
        // c++ 14 的 lambda 中 auto 作为参数
        ForEachTuple(std::make_tuple(1, 2.1, "Hello"), [](const auto& value) -> void { std::cout << value << std::endl; });
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    基于springboot财务管理系统设计与实现-计算机毕业设计源码+LW文档
    Json序列化与反序列化导致多线程运行速度和单线程运行速度一致问题
    【实战技能】单片机bootloader的CANFD,I2C,SPI和串口方式更新APP视频教程(2022-08-01)
    Redis配置与优化
    《HTML+CSS+JavaScript》之第21章 盒子模型
    行为型:迭代器模式
    day7【代码随想录】移除链表元素
    【无标题】
    安全框架Spring Security是什么?如何理解Spring Security的权限管理?
    写作系列之contribution
  • 原文地址:https://blog.csdn.net/feng__shuai/article/details/134301242