C++11: Compile-time Array with Logarithmic Evaluation Depth

后端 未结 3 463
终归单人心
终归单人心 2020-11-29 03:29

One way to implement a C++11 array that has its elements initialized by a function of their index calculated by the compiler and have the results stored in the data section

相关标签:
3条回答
  • 2020-11-29 04:03

    In c++14 with general constexpression function needn't any sequence, make_sequence

    static constexpr int f(int i) noexcept { return i * 2; }
    
    template< int N, typename F >
    static constexpr std::array<int,N> generate_array( F fo ) noexcept
    {
         std::array< int, N > result{}; // init with zero
         int i = 0; 
         for( auto& x : result) x = fo(++i);
    
         return result;
    }
    
    // test
    constexpr auto arr = generate_array<10>( f );
    

    Only has one problem, there is no compiler which can compile it :)

    0 讨论(0)
  • 2020-11-29 04:14

    The only tail recursive template, that's causing the linear template instantiation depth, is the construction of the list of integers in the template parameter list of S.

    This can be done in logarithmic instantiation depth, as you suggest:

    template <int ... Ints> struct seq;
    
    template <int Start, int End> 
    struct range
    {
      typedef concat_seq<range<Start, Start+(End-Start)/2>::type, range<Start+(End-Start)/2, End>::type>::type type;
    };
    
    template<int Singleton>
    struct range<Singleton, Singleton+1>
    {
      typedef seq<Singleton> type;
    };
    
    template <int NoSingleton>
    struct range<NoSinleton, NoSingleton>
    {
      typedef seq<> type;
    };
    

    Add a bunch of typenames where appropriate, implement concat_seq (easy), extract the argument list for fs from range<0, N>::type and there you go.

    0 讨论(0)
  • 2020-11-29 04:26

    If what you're using in the code is a weird form of the indices trick, here's an implementation that has O(log N) instantiations:

    // using aliases for cleaner syntax
    template<class T> using Invoke = typename T::type;
    
    template<unsigned...> struct seq{ using type = seq; };
    
    template<class S1, class S2> struct concat;
    
    template<unsigned... I1, unsigned... I2>
    struct concat<seq<I1...>, seq<I2...>>
      : seq<I1..., (sizeof...(I1)+I2)...>{};
    
    template<class S1, class S2>
    using Concat = Invoke<concat<S1, S2>>;
    
    template<unsigned N> struct gen_seq;
    template<unsigned N> using GenSeq = Invoke<gen_seq<N>>;
    
    template<unsigned N>
    struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
    
    template<> struct gen_seq<0> : seq<>{};
    template<> struct gen_seq<1> : seq<0>{};
    
    // example
    
    template<unsigned... Is>
    void f(seq<Is...>);
    
    int main(){
      f(gen_seq<6>());
    }
    

    Live example.

    0 讨论(0)
提交回复
热议问题