# [ACCEPTED]-C++11: Compile Time Calculation of Array-constexpr

Score: 31

There is a pure C++11 (no boost, no macros 8 too) solution to this problem. Using the 7 same trick as this answer we can build a sequence of 6 numbers and unpack them to call `f` to construct 5 a `std::array`:

``````#include <array>
#include <algorithm>
#include <iterator>
#include <iostream>

template<int ...>
struct seq { };

template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };

template<int ...S>
struct gens<0, S...> {
typedef seq<S...> type;
};

constexpr int f(int n) {
return n;
}

template <int N>
class array_thinger {
typedef typename gens<N>::type list;

template <int ...S>
static constexpr std::array<int,N> make_arr(seq<S...>) {
return std::array<int,N>{{f(S)...}};
}
public:
static constexpr std::array<int,N> arr = make_arr(list());
};

template <int N>
constexpr std::array<int,N> array_thinger<N>::arr;

int main() {
std::copy(begin(array_thinger<10>::arr), end(array_thinger<10>::arr),
std::ostream_iterator<int>(std::cout, "\n"));
}
``````

(Tested with g++ 4.7)

You could skip `std::array` entirely 4 with a bit more work, but I think in this 3 instance it's cleaner and simpler to just 2 use `std::array`.

You can also do this recursively:

``````#include <array>
#include <functional>
#include <algorithm>
#include <iterator>
#include <iostream>

constexpr int f(int n) {
return n;
}

template <int N, int ...Vals>
constexpr
typename std::enable_if<N==sizeof...(Vals),std::array<int, N>>::type
make() {
return std::array<int,N>{{Vals...}};
}

template <int N, int ...Vals>
constexpr
typename std::enable_if<N!=sizeof...(Vals), std::array<int,N>>::type
make() {
return make<N, Vals..., f(sizeof...(Vals))>();
}

int main() {
const auto arr = make<10>();
std::copy(begin(arr), end(arr), std::ostream_iterator<int>(std::cout, "\n"));
}
``````

Which 1 is arguably simpler.

Score: 4

Boost.Preprocessor can help you. The restriction, however, is 5 that you have to use integral literal such 4 as `10` instead of `N` (even be it compile-time 3 constant):

``````#include <iostream>

#include <boost/preprocessor/repetition/enum.hpp>

#define VALUE(z, n, text) f(n)

//ideone doesn't support Boost for C++11, so it is C++03 example,
//so can't use constexpr in the function below
int f(int x) { return x * 10; }

int main() {
int const a[] = { BOOST_PP_ENUM(10, VALUE, ~) };  //N = 10
std::size_t const n = sizeof(a)/sizeof(int);
std::cout << "count = " << n << "\n";
for(std::size_t i = 0 ; i != n ; ++i )
std::cout << a[i] << "\n";
return 0;
}
``````

Output (ideone):

``````count = 10
0
10
20
30
40
50
60
70
80
90
``````

The macro in the following 2 line:

``````int const a[] = { BOOST_PP_ENUM(10, VALUE, ~) };
``````

expands to this:

``````int const a[] = {f(0), f(1), ... f(9)};
``````

A more detail explanation 1 is here:

Score: 4

If you want the array to live in static 3 memory, you could try this:

``````template<class T> struct id { typedef T type; };
template<int...> struct int_pack {};
template<int N, int...Tail> struct make_int_range
: make_int_range<N-1,N-1,Tail...> {};
template<int...Tail> struct make_int_range<0,Tail...>
: id<int_pack<Tail...>> {};

#include <array>

constexpr int f(int n) { return n*(n+1)/2; }

template<class Indices = typename make_int_range<10>::type>
struct my_lookup_table;
template<int...Indices>
struct my_lookup_table<int_pack<Indices...>>
{
static const int size = sizeof...(Indices);
typedef std::array<int,size> array_type;
static const array_type& get()
{
static const array_type arr = {{f(Indices)...}};
return arr;
}
};

#include <iostream>

int main()
{
auto& lut = my_lookup_table<>::get();
for (int i : lut)
std::cout << i << std::endl;
}
``````

If you want a 2 local copy of the array to work on, simply 1 remove the ampersand.

Score: 3

There are quite a few great answers here. The 8 question and tags specify `c++11`, but as a few 7 years have passed, some (like myself) stumbling 6 upon this question may be open to using 5 `c++14`. If so, it is possible to do this very 4 cleanly and concisely using `std::integer_sequence`; moreover, it 3 can be used to instantiate much longer arrays, since 2 the current "Best I Have" is limited by 1 recursion depth.

``````constexpr std::size_t f(std::size_t x) { return x*x; } // A constexpr function
constexpr std::size_t N = 5; // Length of array

using TSequence = std::make_index_sequence<N>;

static_assert(std::is_same<TSequence, std::integer_sequence<std::size_t, 0, 1, 2, 3, 4>>::value,
"Make index sequence uses std::size_t and produces a parameter pack from [0,N)");

using TArray = std::array<std::size_t,N>;

// When you call this function with a specific std::integer_sequence,
// the parameter pack i... is used to deduce the the template parameter
// pack.  Once this is known, this parameter pack is expanded in
// the body of the function, calling f(i) for each i in [0,N).

template<std::size_t...i>
constexpr TArray
get_array(std::integer_sequence<std::size_t,i...>)
{
return TArray{{ f(i)... }};
}

int main()
{

constexpr auto s = TSequence();
constexpr auto a = get_array(s);

for (const auto &i : a) std::cout << i << " ";  // 0 1 4 9 16

return EXIT_SUCCESS;

}
``````
Score: 2

I slightly extended the answer from Flexo 3 and Andrew Tomazos so that the user can 2 specify the computational range and the 1 function to be evaluated.

``````#include <array>
#include <iostream>
#include <iomanip>

template<typename ComputePolicy, int min, int max, int ... expandedIndices>
struct ComputeEngine
{
static const int lengthOfArray = max - min + sizeof... (expandedIndices) + 1;
typedef std::array<typename ComputePolicy::ValueType, lengthOfArray> FactorArray;

static constexpr FactorArray compute( )
{
return ComputeEngine<ComputePolicy, min, max - 1, max, expandedIndices...>::compute( );
}
};

template<typename ComputePolicy, int min, int ... expandedIndices>
struct ComputeEngine<ComputePolicy, min, min, expandedIndices...>
{
static const int lengthOfArray = sizeof... (expandedIndices) + 1;
typedef std::array<typename ComputePolicy::ValueType, lengthOfArray> FactorArray;

static constexpr FactorArray compute( )
{
return FactorArray { { ComputePolicy::compute( min ), ComputePolicy::compute( expandedIndices )... } };
}
};

/// compute 1/j
struct ComputePolicy1
{
typedef double ValueType;

static constexpr ValueType compute( int i )
{
return i > 0 ? 1.0 / i : 0.0;
}
};

/// compute j^2
struct ComputePolicy2
{
typedef int ValueType;

static constexpr ValueType compute( int i )
{
return i * i;
}
};

constexpr auto factors1 = ComputeEngine<ComputePolicy1, 4, 7>::compute( );
constexpr auto factors2 = ComputeEngine<ComputePolicy2, 3, 9>::compute( );

int main( void )
{
using namespace std;

cout << "Values of factors1" << endl;
for ( int i = 0; i < factors1.size( ); ++i )
{
cout << setw( 4 ) << i << setw( 15 ) << factors1[i] << endl;
}
cout << "------------------------------------------" << endl;

cout << "Values of factors2" << endl;
for ( int i = 0; i < factors2.size( ); ++i )
{
cout << setw( 4 ) << i << setw( 15 ) << factors2[i] << endl;
}

return 0;
}
``````
Score: 1

Here's a more concise answer where you explicitly 1 declare the elements in the original sequence.

``````#include <array>

constexpr int f(int i) { return 2 * i; }

template <int... Ts>
struct sequence
{
using result = sequence<f(Ts)...>;
static std::array<int, sizeof...(Ts)> apply() { return {{Ts...}}; }
};

using v1 = sequence<1, 2, 3, 4>;
using v2 = typename v1::result;

int main()
{
auto x = v2::apply();
return 0;
}
``````
Score: 1

``````#include <array>
#include <iostream>

constexpr int f(int i) { return 2 * i; }

template <int N, int... Ts>
struct t { using type = typename t<N - 1, Ts..., 101 - N>::type; };

template <int... Ts>
struct t<0u, Ts...>
{
using type = t<0u, Ts...>;
static std::array<int, sizeof...(Ts)> apply() { return {{f(Ts)...}}; }
};

int main()
{
using v = typename t<100>::type;
auto x = v::apply();
}
``````

0

Score: 0

I don't think that's the best way to do 2 this, but one can try somewhat like this:

``````#include <array>
#include <iostream>
#include <numbers>

constexpr auto pi{std::numbers::pi_v<long double>};

template <typename T>
struct fun
{
T v;
explicit constexpr fun(T a) : v{a * a} {}
};

template <size_t N, typename T, typename F>
struct pcl_arr
{
std::array<T, N> d;

explicit constexpr pcl_arr()
: d{}
{
for (size_t i{}; i < N; d[i] = !i ? 0. : F(pi + i).v, ++i);
}
};

int main()
{
using yummy = pcl_arr<10, long double, fun<long double>>;

constexpr yummy pies;

std::array cloned_pies{pies.d};

//  long double comparison is unsafe
//  it's just for the sake of example
static_assert(pies.d[0] == 0.);

for (const auto & pie : pies.d)         { std::cout << pie << ' '; } std::cout << '\n';
for (const auto & pie : cloned_pies)    { std::cout << pie << ' '; } std::cout << '\n';

return 0;
}
``````

godbolt.org 1 x86-x64 gcc 11.2 -Wall -O3 -std=c++20 output:

`0 17.1528 26.436 37.7192 51.0023 66.2855 83.5687 102.852 124.135 147.418`

`0 17.1528 26.436 37.7192 51.0023 66.2855 83.5687 102.852 124.135 147.418`

More Related questions