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
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 :)
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 typename
s where appropriate, implement concat_seq
(easy), extract the argument list for fs
from range<0, N>::type
and there you go.
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.