C++11: Compile Time Calculation of Array - c++

Suppose I have some constexpr function f:
constexpr int f(int x) { ... }
And I have some const int N known at compile time:
Either
#define N ...;
or
const int N = ...;
as needed by your answer.
I want to have an int array X:
int X[N] = { f(0), f(1), f(2), ..., f(N-1) }
such that the function is evaluated at compile time, and the entries in X are calculated by the compiler and the results are placed in the static area of my application image exactly as if I had used integer literals in my X initializer list.
Is there some way I can write this? (For example with templates or macros and so on)
Best I have: (Thanks to Flexo)
#include <iostream>
#include <array>
using namespace std;
constexpr int N = 10;
constexpr int f(int x) { return x*2; }
typedef array<int, N> A;
template<int... i> constexpr A fs() { return A{{ f(i)... }}; }
template<int...> struct S;
template<int... i> struct S<0,i...>
{ static constexpr A gs() { return fs<0,i...>(); } };
template<int i, int... j> struct S<i,j...>
{ static constexpr A gs() { return S<i-1,i,j...>::gs(); } };
constexpr auto X = S<N-1>::gs();
int main()
{
cout << X[3] << endl;
}

There is a pure C++11 (no boost, no macros too) solution to this problem. Using the same trick as this answer we can build a sequence of numbers and unpack them to call f to construct 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 with a bit more work, but I think in this instance it's cleaner and simpler to just 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 is arguably simpler.

Boost.Preprocessor can help you. The restriction, however, is that you have to use integral literal such as 10 instead of N (even be it compile-time 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 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 is here:
BOOST_PP_ENUM

If you want the array to live in static 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 local copy of the array to work on, simply remove the ampersand.

There are quite a few great answers here. The question and tags specify c++11, but as a few years have passed, some (like myself) stumbling upon this question may be open to using c++14. If so, it is possible to do this very cleanly and concisely using std::integer_sequence; moreover, it can be used to instantiate much longer arrays, since the current "Best I Have" is limited by 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;
}

I slightly extended the answer from Flexo and Andrew Tomazos so that the user can specify the computational range and the 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;
}

Here's a more concise answer where you explicitly 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;
}

How about this one?
#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();
}

I don't think that's the best way to do 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 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

Related

Iterate through std::initializer_list

//parameter pack sum example
constexpr int sum(int N= 0)
{
return N;
}
template<typename ...Args>
constexpr int sum(int first, int second, Args ...N)
{
return first + second + sum(N...);
}
int main()
{
std::cout << sum<int>(1,6,3);
}
Is it possible to make this sum at compile time with std::initializer_list<int> how can i iterate recursive through this.
sum with std::initializer_list might be done the following way in C++11:
template <typename It>
constexpr int sum(It it, It end)
{
return it == end ? 0 : (*it + sum(it + 1, end));
}
constexpr int sum(std::initializer_list<int> ini)
{
return sum(ini.begin(), ini.end());
}
static_assert(sum({1, 2, 3, 4, 5})== 15, "!");
Demo
C++14 allows loop in constexpr function allowing to get rid of recursion:
constexpr int sum(std::initializer_list<int> ini)
{
int res = 0;
for (int e : ini) {
res += e;
}
return res;
}
And in C++20, std::accumulate is marked as constexpr, allowing
constexpr int sum(std::initializer_list<int> ini)
{
return accumulate(ini.begin(), ini.end(), 0);
}
Since C++20, you can use std::reduce as it is marked constexpr:
#include <initializer_list>
#include <numeric>
constexpr int sum(std::initializer_list<int> init) {
return std::reduce(init.begin(), init.end());
}
Here is a solution doing the same more purely without initializer list and constexpr. Works with with gcc-4.4 which has partial C++11 support:
#include <iostream>
template<int N, int ...Args>
struct SumImpl
{
enum { RESULT = N + SumImpl<Args...>::RESULT };
};
template<>
struct SumImpl<0>
{
enum { RESULT = 0 };
};
template<int ...Args>
struct Sum
{
enum { RESULT = SumImpl<Args..., 0>::RESULT };
};
int main()
{
std::cout << Sum<1,6,0,3,23>::RESULT << "\n";
}

Function that can take arrays with different dimensions

Is there a method to create a single function that can take any dimension of vector without overloading?
Currently I have,
someFunction(vector<int> a)
someFunction(vector<vector<int> > a)
someFunction(vector<vector<vector<int> > > a)
However, would it be possible to have a function:
singleFunction(<n-dimension vector>)
{
// Get dimension of array/vector
}
You can use a recursive template function
#include <iostream>
#include <vector>
void func(int el) {
std::cout << el << std::endl;
}
template<typename T>
void func(std::vector<T> v) {
for (const T& el : v) {
func(el);
}
}
int main() {
std::vector<std::vector<int>> v {{1, 2}, {2, 3}};
func(v);
return 0;
}
It's calling it itself for each element until it reaches elements of type int.
To get the dimension you can use the same pattern:
#include <iostream>
#include <vector>
template<typename T>
int someFunction(std::vector<T> v, int dim = 1);
template<>
int someFunction(std::vector<int> v, int dim) {
return dim;
}
template<typename T>
int someFunction(std::vector<T> v, int dim) {
return someFunction(T(), dim + 1);
}
template<typename T>
void singleFunction(std::vector<T> v) {
int dim(someFunction(v));
std::cout << dim << std::endl;
// Do something
}
int main() {
std::vector<std::vector<std::vector<int>>> v {{{1, 0}, {2, 4}}, {{2, 2}, {3, 0}}};
singleFunction(v);
singleFunction(std::vector<std::vector<int>>());
singleFunction(std::vector<int>());
return 0;
}
Here it creates a new object of value type and calls itself until its value type is int. Every time it increments the dimension.
Perhaps you could try this approach, I think this is exactly what you are asking (adopted from std::rank):
#include <iostream>
#include <vector>
#include <type_traits>
template<typename T>
struct vector_rank : public std::integral_constant<std::size_t, 0> {};
template<typename T>
struct vector_rank<std::vector<T>> : public std::integral_constant<std::size_t, vector_rank<T>::value + 1> {};
template<typename T>
size_t GetVectorRank(T)
{
return vector_rank<T>::value;
}
int main()
{
std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> v1;
std::cout << GetVectorRank(v1) << std::endl;
std::vector<std::vector<std::vector<int>>> v2;
std::cout << GetVectorRank(v2) << std::endl;
return 0;
}
The second template be selected recursively while the type is std::vector<T>, the first template will be selected for everything else as well as at the end of recursion. The above example will return:
5
3
Demo: https://ideone.com/CLucGA
With C++17 you can write a pretty simple solution:
template<typename T >
constexpr int func(){
if constexpr (is_vector<typename T::value_type>::value )
return 1+func<typename T::value_type>();
return 1;
}
int main() {
cout<< func<vector<vector<vector<vector<vector<int>>>>>>() <<endl;
return 0;
}
which return 5 as expected.
You need to define is_vector as follows:
template<class T>
struct is_vector{
static bool const value = false;
};
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
A simple template should solve this. From memory:
template <T> singleFunction(vector<T> &t) {
return t.size();
}
you can get the dimension with this code
#include <vector>
#include <iostream>
template<unsigned N, typename T>
struct meta {
static unsigned func() {//terminale recursion case
return N;
}
};
template<unsigned N, typename T>
struct meta<N, std::vector<T> > {//mid recursion case
static unsigned func() {
return meta<N + 1, T>::func();
}
};
template<typename T>
unsigned func(T) { //adapter to deduce the type
return meta<0, T>::func();
}
int main() {
std::cout << func(std::vector<std::vector<std::vector<int> > >()) << std::endl;
std::cout << func(std::vector<int>()) << std::endl;
std::cout << func(int()) << std::endl;
std::cout << func(std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<int> > > > > >()) << std::endl;
return 0;
}
will output
3
1
0
6

Cumulative Product of Template Parameter Pack

I'm trying to initialise a static and constant array with the cumulative product of a template parameter pack:
template <int ...D>
class Foo
{
static const std::array<const Size, sizeof...(D)> _array;
};
template <int...D> const std::array<const int, sizeof...(D)> Foo<D...>::_array =
{ cumulative_product<D...>() };
How do I write the function cumulative_product<>(), such that it transforms D... into the cumulative product of D...? E.g.
Foo<1,2,3,4>::_array;// = {1,1*2,1*2*3,1*2*3*4} = {1,2,6,24}.
Solution: Massive thank you to #bogdan for your excellent C++14 solution, and improvements to my C++11 solution.
#include <array>
#include <iostream>
#define CPP_VERSION 11
#if CPP_VERSION >= 14
// Credit: #bogdan at http://stackoverflow.com/q/37373602/6367128
template<int... Args> constexpr std::array<int, sizeof...(Args)> cumulative_product(int seed = 1) { return{ { seed *= Args ... } }; }
#elif CPP_VERSION == 11
// Acknowledgement: Huge thank you to #bogdan for making the code more portable, concise and readable!
namespace details
{
template<int N, int i, int j, int ...Args> struct c_product_gen // N counts down to zero
{
static constexpr std::array<int, sizeof...(Args)+1> get() { return c_product_gen<N - 1, i*j, Args..., i*j>::get(); }
};
template<int i, int j, int ...Args> struct c_product_gen<0, i, j, Args...> // The end point of the template recursion
{
static constexpr std::array<int, sizeof...(Args)+1> get() { return { { j, Args... } }; }
};
}
template<int... Args> constexpr std::array<int, sizeof...(Args)> cumulative_product() { return details::c_product_gen<sizeof...(Args), 1, Args...>::get(); }
#else // CPP_VERSION < 11
template<int... Args> constexpr std::array<int, sizeof...(Args)> cumulative_product()
{
static_assert(false, "C++ version 11 or greater is required.");
return std::array<int, sizeof...(Args)>();
}
#endif
int main()
{
constexpr auto a = cumulative_product<1,2,3,4,5>();
for(auto i : a) std::cout << i << ' '; // Output: 1 2 6 24 120
std::cout << '\n';
}
#include <array>
#include <utility>
#include <cstddef>
template <int... D, std::size_t... Is>
constexpr std::array<int, sizeof...(D)> cumulative_product(std::index_sequence<Is...>)
{
static_assert(sizeof...(D), "Missing initializers");
int a[]{ D... };
for (int i = 1; i < int(sizeof...(D)); ++i)
{
a[i] *= a[i-1];
}
return {{ a[Is]... }};
}
template <int... D>
constexpr auto cumulative_product()
{
return cumulative_product<D...>(std::make_index_sequence<sizeof...(D)>{});
}
template <int... D>
struct Foo
{
static constexpr std::array<int, sizeof...(D)> _array = cumulative_product<D...>();
};
DEMO

Filling an array during compilation [duplicate]

Hello i'm learning C++11, I'm wondering how to make a constexpr 0 to n array, for example:
n = 5;
int array[] = {0 ... n};
so array may be {0, 1, 2, 3, 4, 5}
In C++14 it can be easily done with a constexpr constructor and a loop:
#include <iostream>
template<int N>
struct A {
constexpr A() : arr() {
for (auto i = 0; i != N; ++i)
arr[i] = i;
}
int arr[N];
};
int main() {
constexpr auto a = A<4>();
for (auto x : a.arr)
std::cout << x << '\n';
}
Unlike those answers in the comments to your question, you can do this without compiler extensions.
#include <iostream>
template<int N, int... Rest>
struct Array_impl {
static constexpr auto& value = Array_impl<N - 1, N, Rest...>::value;
};
template<int... Rest>
struct Array_impl<0, Rest...> {
static constexpr int value[] = { 0, Rest... };
};
template<int... Rest>
constexpr int Array_impl<0, Rest...>::value[];
template<int N>
struct Array {
static_assert(N >= 0, "N must be at least 0");
static constexpr auto& value = Array_impl<N>::value;
Array() = delete;
Array(const Array&) = delete;
Array(Array&&) = delete;
};
int main() {
std::cout << Array<4>::value[3]; // prints 3
}
Based on #Xeo's excellent idea, here is an approach that lets you fill an array of
constexpr std::array<T, N> a = { fun(0), fun(1), ..., fun(N-1) };
where T is any literal type (not just int or other valid non-type template parameter types), but also double, or std::complex (from C++14 onward)
where fun() is any constexpr function
which is supported by std::make_integer_sequence from C++14 onward, but easily implemented today with both g++ and Clang (see Live Example at the end of the answer)
I use #JonathanWakely 's implementation at GitHub (Boost License)
Here is the code
template<class Function, std::size_t... Indices>
constexpr auto make_array_helper(Function f, std::index_sequence<Indices...>)
-> std::array<typename std::result_of<Function(std::size_t)>::type, sizeof...(Indices)>
{
return {{ f(Indices)... }};
}
template<int N, class Function>
constexpr auto make_array(Function f)
-> std::array<typename std::result_of<Function(std::size_t)>::type, N>
{
return make_array_helper(f, std::make_index_sequence<N>{});
}
constexpr double fun(double x) { return x * x; }
int main()
{
constexpr auto N = 10;
constexpr auto a = make_array<N>(fun);
std::copy(std::begin(a), std::end(a), std::ostream_iterator<double>(std::cout, ", "));
}
Live Example
Use C++14 integral_sequence, or its invariant index_sequence
#include <iostream>
template< int ... I > struct index_sequence{
using type = index_sequence;
using value_type = int;
static constexpr std::size_t size()noexcept{ return sizeof...(I); }
};
// making index_sequence
template< class I1, class I2> struct concat;
template< int ...I, int ...J>
struct concat< index_sequence<I...>, index_sequence<J...> >
: index_sequence< I ... , ( J + sizeof...(I) )... > {};
template< int N > struct make_index_sequence_impl;
template< int N >
using make_index_sequence = typename make_index_sequence_impl<N>::type;
template< > struct make_index_sequence_impl<0> : index_sequence<>{};
template< > struct make_index_sequence_impl<1> : index_sequence<0>{};
template< int N > struct make_index_sequence_impl
: concat< make_index_sequence<N/2>, make_index_sequence<N - N/2> > {};
// now, we can build our structure.
template < class IS > struct mystruct_base;
template< int ... I >
struct mystruct_base< index_sequence< I ... > >
{
static constexpr int array[]{I ... };
};
template< int ... I >
constexpr int mystruct_base< index_sequence<I...> >::array[] ;
template< int N > struct mystruct
: mystruct_base< make_index_sequence<N > >
{};
int main()
{
mystruct<20> ms;
//print
for(auto e : ms.array)
{
std::cout << e << ' ';
}
std::cout << std::endl;
return 0;
}
output: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
UPDATE:
You may use std::array:
template< int ... I >
static constexpr std::array< int, sizeof...(I) > build_array( index_sequence<I...> ) noexcept
{
return std::array<int, sizeof...(I) > { I... };
}
int main()
{
std::array<int, 20> ma = build_array( make_index_sequence<20>{} );
for(auto e : ma) std::cout << e << ' ';
std::cout << std::endl;
}
#include <array>
#include <iostream>
template<int... N>
struct expand;
template<int... N>
struct expand<0, N...>
{
constexpr static std::array<int, sizeof...(N) + 1> values = {{ 0, N... }};
};
template<int L, int... N> struct expand<L, N...> : expand<L-1, L, N...> {};
template<int... N>
constexpr std::array<int, sizeof...(N) + 1> expand<0, N...>::values;
int main()
{
std::cout << expand<100>::values[9];
}
For std::array in C++17,
constexpr function are also accepted
Note that the var 'arr' must be initialized by constexpr required.
(initialize: same meaning with answer of #abyx)
#include <array>
constexpr std::array<int, 3> get_array()
{
std::array<int, 3> arr{0};
arr[0] = 9;
return arr;
}
static_assert(get_array().size() == 3);
With C++17 this can be done easily as std::array::begin is marked constexpr.
template<std::size_t N> std::array<int, N + 1> constexpr make_array()
{
std::array<int, N + 1> tempArray{};
int count = 0;
for(int &elem:tempArray)
{
elem = count++;
}
return tempArray;
}
int main()
{
//-------------------------------vv------>pass the size here
constexpr auto arr = make_array<5>();
//lets confirm if all objects have the expected value
for(const auto &elem: arr)
{
std::cout << elem << std::endl; //prints 1 2 3 4 5 with newline in between
}
}
Demo
Using boost preprocessor, it's very simple:
#include <cstdio>
#include <cstddef>
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/comma_if.hpp>
#define IDENTITY(z,n,dummy) BOOST_PP_COMMA_IF(n) n
#define INITIALIZER_n(n) { BOOST_PP_REPEAT(n,IDENTITY,~) }
int main(int argc, char* argv[])
{
int array[] = INITIALIZER_n(25);
for(std::size_t i = 0; i < sizeof(array)/sizeof(array[0]); ++i)
printf("%d ",array[i]);
return 0;
}
OUTPUT:
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
Consider boost::mpl::range_c<int, 0, N> instead.

Create N-element constexpr array in C++11

Hello i'm learning C++11, I'm wondering how to make a constexpr 0 to n array, for example:
n = 5;
int array[] = {0 ... n};
so array may be {0, 1, 2, 3, 4, 5}
In C++14 it can be easily done with a constexpr constructor and a loop:
#include <iostream>
template<int N>
struct A {
constexpr A() : arr() {
for (auto i = 0; i != N; ++i)
arr[i] = i;
}
int arr[N];
};
int main() {
constexpr auto a = A<4>();
for (auto x : a.arr)
std::cout << x << '\n';
}
Unlike those answers in the comments to your question, you can do this without compiler extensions.
#include <iostream>
template<int N, int... Rest>
struct Array_impl {
static constexpr auto& value = Array_impl<N - 1, N, Rest...>::value;
};
template<int... Rest>
struct Array_impl<0, Rest...> {
static constexpr int value[] = { 0, Rest... };
};
template<int... Rest>
constexpr int Array_impl<0, Rest...>::value[];
template<int N>
struct Array {
static_assert(N >= 0, "N must be at least 0");
static constexpr auto& value = Array_impl<N>::value;
Array() = delete;
Array(const Array&) = delete;
Array(Array&&) = delete;
};
int main() {
std::cout << Array<4>::value[3]; // prints 3
}
Based on #Xeo's excellent idea, here is an approach that lets you fill an array of
constexpr std::array<T, N> a = { fun(0), fun(1), ..., fun(N-1) };
where T is any literal type (not just int or other valid non-type template parameter types), but also double, or std::complex (from C++14 onward)
where fun() is any constexpr function
which is supported by std::make_integer_sequence from C++14 onward, but easily implemented today with both g++ and Clang (see Live Example at the end of the answer)
I use #JonathanWakely 's implementation at GitHub (Boost License)
Here is the code
template<class Function, std::size_t... Indices>
constexpr auto make_array_helper(Function f, std::index_sequence<Indices...>)
-> std::array<typename std::result_of<Function(std::size_t)>::type, sizeof...(Indices)>
{
return {{ f(Indices)... }};
}
template<int N, class Function>
constexpr auto make_array(Function f)
-> std::array<typename std::result_of<Function(std::size_t)>::type, N>
{
return make_array_helper(f, std::make_index_sequence<N>{});
}
constexpr double fun(double x) { return x * x; }
int main()
{
constexpr auto N = 10;
constexpr auto a = make_array<N>(fun);
std::copy(std::begin(a), std::end(a), std::ostream_iterator<double>(std::cout, ", "));
}
Live Example
Use C++14 integral_sequence, or its invariant index_sequence
#include <iostream>
template< int ... I > struct index_sequence{
using type = index_sequence;
using value_type = int;
static constexpr std::size_t size()noexcept{ return sizeof...(I); }
};
// making index_sequence
template< class I1, class I2> struct concat;
template< int ...I, int ...J>
struct concat< index_sequence<I...>, index_sequence<J...> >
: index_sequence< I ... , ( J + sizeof...(I) )... > {};
template< int N > struct make_index_sequence_impl;
template< int N >
using make_index_sequence = typename make_index_sequence_impl<N>::type;
template< > struct make_index_sequence_impl<0> : index_sequence<>{};
template< > struct make_index_sequence_impl<1> : index_sequence<0>{};
template< int N > struct make_index_sequence_impl
: concat< make_index_sequence<N/2>, make_index_sequence<N - N/2> > {};
// now, we can build our structure.
template < class IS > struct mystruct_base;
template< int ... I >
struct mystruct_base< index_sequence< I ... > >
{
static constexpr int array[]{I ... };
};
template< int ... I >
constexpr int mystruct_base< index_sequence<I...> >::array[] ;
template< int N > struct mystruct
: mystruct_base< make_index_sequence<N > >
{};
int main()
{
mystruct<20> ms;
//print
for(auto e : ms.array)
{
std::cout << e << ' ';
}
std::cout << std::endl;
return 0;
}
output: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
UPDATE:
You may use std::array:
template< int ... I >
static constexpr std::array< int, sizeof...(I) > build_array( index_sequence<I...> ) noexcept
{
return std::array<int, sizeof...(I) > { I... };
}
int main()
{
std::array<int, 20> ma = build_array( make_index_sequence<20>{} );
for(auto e : ma) std::cout << e << ' ';
std::cout << std::endl;
}
#include <array>
#include <iostream>
template<int... N>
struct expand;
template<int... N>
struct expand<0, N...>
{
constexpr static std::array<int, sizeof...(N) + 1> values = {{ 0, N... }};
};
template<int L, int... N> struct expand<L, N...> : expand<L-1, L, N...> {};
template<int... N>
constexpr std::array<int, sizeof...(N) + 1> expand<0, N...>::values;
int main()
{
std::cout << expand<100>::values[9];
}
For std::array in C++17,
constexpr function are also accepted
Note that the var 'arr' must be initialized by constexpr required.
(initialize: same meaning with answer of #abyx)
#include <array>
constexpr std::array<int, 3> get_array()
{
std::array<int, 3> arr{0};
arr[0] = 9;
return arr;
}
static_assert(get_array().size() == 3);
With C++17 this can be done easily as std::array::begin is marked constexpr.
template<std::size_t N> std::array<int, N + 1> constexpr make_array()
{
std::array<int, N + 1> tempArray{};
int count = 0;
for(int &elem:tempArray)
{
elem = count++;
}
return tempArray;
}
int main()
{
//-------------------------------vv------>pass the size here
constexpr auto arr = make_array<5>();
//lets confirm if all objects have the expected value
for(const auto &elem: arr)
{
std::cout << elem << std::endl; //prints 1 2 3 4 5 with newline in between
}
}
Demo
Using boost preprocessor, it's very simple:
#include <cstdio>
#include <cstddef>
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/comma_if.hpp>
#define IDENTITY(z,n,dummy) BOOST_PP_COMMA_IF(n) n
#define INITIALIZER_n(n) { BOOST_PP_REPEAT(n,IDENTITY,~) }
int main(int argc, char* argv[])
{
int array[] = INITIALIZER_n(25);
for(std::size_t i = 0; i < sizeof(array)/sizeof(array[0]); ++i)
printf("%d ",array[i]);
return 0;
}
OUTPUT:
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
Consider boost::mpl::range_c<int, 0, N> instead.