What's the best way for setting an std::vector<int> to a range, e.g. all numbers between 3 and 16?
You could use std::iota if you have C++11 support or are using the STL:
std::vector<int> v(14);
std::iota(v.begin(), v.end(), 3);
or implement your own if not.
If you can use boost, then a nice option is boost::irange:
std::vector<int> v;
boost::push_back(v, boost::irange(3, 17));
std::vector<int> myVec;
for( int i = 3; i <= 16; i++ )
myVec.push_back( i );
See e.g. this question
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
template<class OutputIterator, class Size, class Assignable>
void iota_n(OutputIterator first, Size n, Assignable value)
{
std::generate_n(first, n, [&value]() {
return value++;
});
}
int main()
{
std::vector<int> v; // no default init
v.reserve(14); // allocate 14 ints
iota_n(std::back_inserter(v), 14, 3); // fill them with 3...16
std::for_each(v.begin(), v.end(), [](int const& elem) {
std::cout << elem << "\n";
});
return 0;
}
Output on Ideone
std::iota - is useful, but it requires iterator, before creation vector, .... so I take own solution.
#include <iostream>
#include <vector>
template<int ... > struct seq{ typedef seq type;};
template< typename I, typename J> struct add;
template< int...I, int ...J>
struct add< seq<I...>, seq<J...> > : seq<I..., (J+sizeof...(I)) ... >{};
template< int N>
struct make_seq : add< typename make_seq<N/2>::type,
typename make_seq<N-N/2>::type > {};
template<> struct make_seq<0>{ typedef seq<> type; };
template<> struct make_seq<1>{ typedef seq<0> type; };
template<int start, int step , int ... I>
std::initializer_list<int> range_impl(seq<I... > )
{
return { (start + I*step) ...};
}
template<int start, int finish, int step = 1>
std::initializer_list<int> range()
{
return range_impl<start, step>(typename make_seq< 1+ (finish - start )/step >::type {} );
}
int main()
{
std::vector<int> vrange { range<3, 16>( )} ;
for(auto x : vrange)std::cout << x << ' ';
}
Output:
3 4 5 6 7 8 9 10 11 12 13 14 15 16
Try to use std::generate. It can generate values for a container based on a formula
std::vector<int> v(size);
std::generate(v.begin(),v.end(),[n=0]()mutable{return n++;});
Related
If I have a range and I want to transform adjacent pairs is there a boost
range adaptor to do this?
for example
std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
auto b = a
| boost::range::transformed([](int x, int y){return x+y;});
and the output would be
3, 5
EDIT
I have made an attempt at a range adaptor
// Base class for holders
template< class T >
struct holder
{
T val;
holder( T t ) : val(t)
{ }
};
// Transform Adjacent
template <typename BinaryFunction> struct transformed_adjacent_holder
: holder
{
transformed_adjacent_holder(BinaryFunction fn) : holder<BinaryFunction>(fn)
};
template <typename BinaryFunction> transform_adjacent
(BinaryFunction fn)
{ return transformed_adjacent_holder<BinaryFunction>(fn); }
template< class InputRng, typename BinFunc>
inline auto Foo(const InputRng& r, const transformed_adjacent_holder<BinFunc> & f)
-> boost::any_range
< std::result_of(BinFunc)
, boost::forward_traversal_tag
, int
, std::ptrdiff_t
>
{
typedef boost::range_value<InputRng>::type T;
T previous;
auto unary = [&](T const & t) {auto tmp = f.val(previous, t); previous = t; return tmp; };
return r | transformed(unary);
}
However I don't know how to deduce the return type of the | operator. If I can do this then the adaptor is almost solved.
You can maintain a dummy variable
int prev=0;
auto b = a | transformed([&prev](int x){int what = x+prev;prev=x;return what;});
No. But you can use the range algorithm:
Live On Wandbox
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <vector>
#include <iostream>
using namespace boost::adaptors;
int main() {
std::vector<int> a { 1,2,3 };
auto n = a.size();
if (n > 0) {
auto out = std::ostream_iterator<int>(std::cout, "\n");
boost::transform(a, a | sliced(1, n), out, [](int x, int y) { return x + y; });
}
}
This uses the binary transform on a and a slice of itself.
Prints
3
5
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.
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.
If I got that right I can use this to iterate over a fixed range:
for(int i: {1, 2, 3, 4, 5})
do_sth(i);
And this is the same thing:
vector<int> v{1, 2, 3, 4, 5};
for(int i: v)
do_sth(i);
But what if I want to iterate over the range of 1, ..., 100 and already know that at compile time?
What is the most beautiful way to do that?
What the most efficient?
What the shortest?
Edit: of course I could write a regular for loop, but the actual use case would involve more complicated content than ints.
I just oversimplified the example a bit.
for( int i = 1; i <= 100; ++i )
{
do_sth( i );
}
?
You can "easily" write a for-range-compatible class that represents an integer range. You just have to write the iterators for it.
Or you can use Boost.Range's counting_range, which is exactly that.
If you really want it in a container, you can fill a container using the std::iota function. Otherwise use a normal for loop.
Use a range-for with a function template:
namespace detail
{
template <int... Is>
struct index { };
template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
template <int... Is>
struct gen_seq<0, Is...> : index<Is...> { };
}
template <int... Is>
std::array<int, sizeof...(Is)> range(detail::index<Is...>)
{
return {{ Is... }};
}
template <int N>
std::array<int, N> range()
{
return range(detail::gen_seq<N>{});
}
Example:
for (auto i : range<5>())
{
do_sth(i);
}
Example of an iterator-based technique, as Sebastian Redl mentioned:
class range {
public:
struct rangeIt{
rangeIt(int v) : _v(v){}
int operator*()const{return _v;}
void operator++(){_v++;}
bool operator!=(const rangeIt & other)const{ return _v != other._v;}
private:
int _v;
};
range(int a, int b):_a(a),_b(b){}
rangeIt begin() const { return rangeIt(_a); }
rangeIt end() const { return rangeIt(_b); }
private:
int _a, _b;
};
Then it can be used like this:
for(int i : range(0, 100)) {
printf("%d\n", i);
}
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> operator"" _r(const char* text, const size_t)
{
string txt(text);
auto delim = txt.find('-');
auto first = txt.substr( 0, delim);
auto second = txt.substr(delim + 1);
int lower = stoi(first);
int upper = stoi(second);
vector<int> rval(upper - lower);
generate(rval.begin(), rval.end(), [&]{ return lower++; } );
return rval;
}
int main()
{
for(auto& el : "10-100"_r)
cout<<el<<"\n";
}
Big runtime overhead, error prone ( mainly my implementation )... just the way I like it !
But it does solve the problem and even has a not-that-ugly syntax :)
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