struct for coordinates;
struct point{
int x_, y_;
}
Assume we have a coordinates as it is defined above. In addition to this struct i want to create a function which takes as many parameters as user wants(for instance a function to find the barycentre of three or more points). So i have decided to use variadic templates. But i recognized that i am lack of info about variadic templates.
As to calculate barycentre, you should add all x's, divide the sum to element count. And do it for y's of elements and return a point. Can you lead me a way to implement this.
C++17's fold-expressions make this a breeze:
template <class... Points>
point barycentre(Points... points) {
point const sum{
(points.x_ + ...),
(points.y_ + ...)
};
int const num = sizeof...(Points);
return {
sum.x_ / num,
sum.y_ / num
};
}
See it live on Coliru
If you are using C++14 you could simply iterate through points in constexpr function, e.g. like this (example borrowed from Quentin's answer):
#include <iostream>
struct point{
int x_, y_;
};
template <class... Points>
constexpr point barycentre(Points... points) {
point ps[] = {points...};
point result {0, 0};
for (std::size_t i = 0; i < sizeof...(points); i++) {
result.x_ += ps[i].x_;
result.y_ += ps[i].y_;
}
result.x_ /= sizeof...(points);
result.y_ /= sizeof...(points);
return result;
}
int main() {
constexpr auto bary = barycentre(point{0, 0}, point{2, 2});
std::cout << "(" << bary.x_ << ", " << bary.y_ << ")\n";
}
[live demo]
And some C++11:
#include <iostream>
#include <array>
#include <type_traits>
struct point{
int x_, y_;
};
template <std::size_t I, std::size_t N>
constexpr typename std::enable_if<I + 1 == N, point>::type barysum(std::array<point, N> const &points) {
return point{ points[I].x_, points[I].y_ };
}
template <std::size_t I, std::size_t N>
constexpr typename std::enable_if<I + 1 != N, point>::type barysum(std::array<point, N> const &points) {
return point{ points[I].x_ + barysum<I+1>(points).x_, points[I].y_ + barysum<I+1>(points).y_ };
}
template <std::size_t N>
constexpr point barycentre_impl(std::array<point, N> const points_array) {
return point{ barysum<0>(points_array).x_ / static_cast<int>(N), barysum<0>(points_array).y_ / static_cast<int>(N)};
}
template <class... Pts>
constexpr point barycentre(Pts... pts) {
return barycentre_impl<sizeof...(Pts)>( {{pts...}} );
}
int main() {
constexpr auto bary = barycentre(point{0, 0}, point{2, 2});
std::cout << "(" << bary.x_ << ", " << bary.y_ << ")\n";
}
[live demo]
Initializer list is simpler for taking elements of the same type.
Point average(std::initializer_list<Point> list)
{
int x = 0, y = 0;
for(auto &i: list) {x += i.x_; y += i.y_;}
return {x / list.size(), y / list.size()};
}
Variadic templates is generic on types, so it doesn't fit for your case. It doesn't make your code execute faster in any way, just bloating the binary.
Related
//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";
}
My Problem is the following. I want to sort a list of types based on a list of constexpr values. The problem can be boiled down to this function:
template <typename U, typename V>
auto min(U,V) -> std::conditional_t<U::value < V::value, U, V>
{ return {}; }
whereas value must be some static constexpr member of each type, respecively.
The following snippet demonstrates the usage:
// (I)
// This must even be declared outside of a function body due to the statics :(
struct X { static constexpr double value = 2.; };
struct Y { static constexpr double value = 1.; };
int main()
{
X x;
Y y;
auto z = min(x,y);
std::cout << typeid(z).name() << " : " << z.value << std::endl;
}
My goal is to provide the value as I call the function. The closest thing I got to this goal is
the following
template <double (*F)()>
struct Value { static constexpr double value = F(); };
which can be called like this using lambdas:
// (II)
auto w = min(Value<[]{ return 3.14; }>{}, Value<[]{ return 2.71; }>{});
std::cout << typeid(w).name() << " : " << w.value << std::endl;
The actual type to be sorted can be an additional parameter.
The problem is that the above is not valid C++ according to the standard. However, the latest clang does compile
this gracefully.
Now, my question is: Is there another standard compliant way to achieve the above (listing (II)), that is, defining a function that
computes a type based on constexor objects provided inplace (in some way) as the function argument?
P.S.: I'm aware of the solution using std::integral_constant. This, however, is limited to integral types only. I'm interested in a solution that works for all constexpr objects, in particular floating point types, and strings.
Edit:
To deal with floating point values as well as integral types scenarios you could make use of user defined literal template e.g.:
#include <type_traits>
#include <utility>
#include <typeinfo>
#include <iostream>
template <class FloatingPointType, class... Cs>
constexpr FloatingPointType char_list_to_(Cs... cs) {
char arr[] = {cs...};
FloatingPointType lhs = 0;
bool contains_dot = false;
for (std::size_t i = 0; i < sizeof...(Cs) && !(contains_dot |= (arr[i] == '.')); i++) {
lhs *= 10;
lhs += arr[i] - '0';
}
FloatingPointType rhs = 0;
for (int i = sizeof...(Cs) - 1; i > 0 && arr[i] != '.'; i--) {
rhs /= 10;
rhs += arr[i] - '0';
}
rhs /= 10;
return (contains_dot)?lhs+rhs:lhs;
}
template <class FloatingPointType, char... Cs>
struct FloatingPointValue {
static constexpr FloatingPointType value = char_list_to_<FloatingPointType>(Cs...);
constexpr operator FloatingPointType() {
return value;
}
};
template <class FloatingPointType, char... Cs>
constexpr FloatingPointType FloatingPointValue<FloatingPointType, Cs...>::value;
template <char... Cs>
FloatingPointValue<double, Cs...> operator""_fv() {
return {};
}
template <typename U, typename V>
auto min(U,V) -> std::conditional_t<(U{}<V{}), U, V>
{ return {}; }
int main() {
auto w = min(3.14_fv, 2.71_fv);
std::cout << typeid(w).name() << " : " << w.value << std::endl;
}
Output:
18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE : 2.71
Output of c++filt -t 18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE:
FloatingPointValue<double, (char)50, (char)46, (char)55, (char)49>
[live demo]
But if you wish to apply the same to string literal there is currently a lack of support of the feature caused by a c++ standard. There is however a gnu extension supported by clang and gcc if you are capable to accept less portable option:
#include <type_traits>
#include <utility>
#include <typeinfo>
#include <iostream>
template <class CharT, CharT... Cs>
struct Value {
static constexpr std::size_t size = sizeof...(Cs);
static constexpr CharT const value[sizeof...(Cs) + 1] = {Cs..., '\0'};
template <class RHS>
constexpr bool operator<(RHS) {
for (std::size_t i = 0; i < size && i < RHS::size; i++) {
if (value[i] != RHS::value[i]) {
return value[i] < RHS::value[i];
}
}
return size < RHS::size;
}
};
template <class CharT, CharT... Cs>
constexpr CharT const Value<CharT, Cs...>::value[sizeof...(Cs) + 1];
template <class CharT, CharT... Cs>
Value<CharT, Cs...> operator""_v() {
return {};
}
template <typename U, typename V>
auto min(U,V) -> std::conditional_t<(U{}<V{}), U, V>
{ return {}; }
int main() {
auto w = min("cde"_v, "abc"_v);
std::cout << typeid(w).name() << " : " << w.value << std::endl;
}
Output:
5ValueIcJLc97ELc98ELc99EEE : abc
Output of c++filt -t 5ValueIcJLc97ELc98ELc99EEE:
Value<char, (char)97, (char)98, (char)99>
[live demo]
I'm working on porting some Julia code to C++ and have run into a problem. To make matters worse I'm not very familiar with the C++ nomenclature, so haven't been able to google my way out.
Basically, I'm trying to figure out how to refer to a template (is this a template alias?) so I can use it later, i.e., to refer to a type. I've tried various incantations involving using, typename, and template, but nothing seems to make my compiler happy. I have managed to produce something which does what I want (see below), but it is pretty nasty. Is there a better way? Any reasonable C++ is fine.
The following code is a minimal example of what I'm trying to achieve
#include <iostream>
#include <type_traits>
template<int n, template<int> class T>
int unwrap(T<n>& x) { return n; }
template<int n>
struct A { static const char name = 'A'; };
template<int n>
struct B { static const char name = 'B'; };
template<bool flag>
struct promote_if {
template<int n> using type = A<n>;
};
template<>
struct promote_if<true> {
template<int n> using type = B<n>;
};
template<int m, int n,
template<int> class X,
template<int> class Y,
template<int> class Z>
struct Stuff { static const int seven = 7; };
// Add type parameters and return
// B<m + n> if X or Y is a B,
// otherwise return A<m + n>
template<int m, int n, template<int> class X, template<int> class Y>
auto add(X<m>& x, Y<n>& y) {
static const bool any = std::is_base_of<B<m>, X<m>>::value || std::is_base_of<B<n>, Y<n>>::value;
// This works, but is gross
std::cout << Stuff<m,n,promote_if<any>::template type,X,Y>::seven << "\n";
typename promote_if<any>::template type<m + n> z;
// Something like this is what I'm trying to achieve
// using T = typename promote_if<any>::template type;
// T<m + n> z;
// std::cout << Stuff<m,n,T,X,Y>::seven << "\n";
return z;
}
int main(int argc, char const *argv[]) {
A<1> a;
B<2> b;
auto c = add(a, a);
std::cout << "c = add(a, a) = " << c.name << "<" << unwrap(c) << ">\n";
auto d = add(a, b);
std::cout << "d = add(a, b) = " << d.name << "<" << unwrap(d) << ">\n";
return 0;
}
// Output
// Stuff is 7
// c = add(a, a) = A<2>
// Stuff is 7
// d = add(a, b) = B<3>
Instead of
template<int m, int n, template<int> class X, template<int> class Y>
auto add(X<m>& x, Y<n>& y) {
static const bool any = std::is_base_of<B<m>, X<m>>::value || std::is_base_of<B<n>, Y<n>>::value;
// This works, but is gross
std::cout << Stuff<m,n,promote_if<any>::template type,X,Y>::seven << "\n";
typename promote_if<any>::template type<m + n> z;
// Something like this is what I'm trying to achieve
// using T = typename promote_if<any>::template type;
// T<m + n> z;
// std::cout << Stuff<m,n,T,X,Y>::seven << "\n";
return z;
}
try
// Add type parameters and return
// B<m + n> if X or Y is a B,
// otherwise return A<m + n>
template<int m, int n, template<int> class X, template<int> class Y>
auto add(X<m>& x, Y<n>& y) {
static const bool any = std::is_base_of<B<m>, X<m>>::value || std::is_base_of<B<n>, Y<n>>::value;
using T = promote_if<any>;
typename T::template type<m + n> z;
std::cout << Stuff<m,n,T::template type,X,Y>::seven << "\n";
return z;
}
I just tried some combinations of typename and template and so on and let the g++ compiler's diagnostics steer me towards working code.
I think this is still ugly, though.
A probably better solution would be to rethink the whole thing and change the design.
The following example might seem nonsensical, but it's part of a larger high-performance code where the presented technique makes sense. I mention this just in case someone should suspect an XY question - it's most probably not.
I have a function with templated/compile-time operand:
template <int M>
int mul(int x){
return M * x;
}
Now I want to do the same for double, what is - of course - not allowed:
template <double M> // you can't do that!
int mul(double x){
return M * x;
}
So to still put in the double at compile time, I only see the following solution:
// create my constants
struct SevenPointFive{
static constexpr double VAL = 7.5;
}
struct ThreePointOne{
static constexpr double VAL = 3.1;
}
// modified function
template <class M>
int mul(double x){
return M::VAL * x;
}
// call it
double a = mul<SevenPointFive>(3.2);
double b = mul<ThreePointOne>(a);
Is there a better solution for the problem to somehow pass a double constant in a template parameter, without creating a struct for each value?
(I'm interested in a solution which actually uses double/float, not a hack with using two ints to create a rational number or fixed point ideas such as y = 0.01 * M * x.)
In C++11, it is not necessary to use templates at all. Simply use constexpr (generalised constant expressions) in a different way than you are.
#include <iostream>
constexpr double mul(double x, double y)
{
return x*y;
}
int main()
{
std::cout << mul(2.3, 3.4) << '\n';
double x;
std::cin >> x; // to demonstrate constexpr works with variables
std::cout << mul(2.3, x) << '\n';
}
Although I say templates aren't necessary (which they aren't in the example given) these can be templated if needed
template <class T> constexpr T mul(T x, T y) {return x*y;}
or (if you want to use the function for types that are better passed by const reference)
template <class T> constexpr T mul(const T &x, const T &y) {return x*y;}
You can conveniently pass floating point values in template parameters using user-defined literals.
Just write a literal that creates your envelope class. Then you can write something like
mul<decltype(3.7_c)>(7)
Or even better, have your function take the argument by value so you can write
mul(3.7_c, 7)
the compiler will make that just as efficient.
Below's an example of code that does this:
#include <iostream>
template <int Value, char...>
struct ParseNumeratorImpl {
static constexpr int value = Value;
};
template <int Value, char First, char... Rest>
struct ParseNumeratorImpl<Value, First, Rest...> {
static constexpr int value =
(First == '.')
? ParseNumeratorImpl<Value, Rest...>::value
: ParseNumeratorImpl<10 * Value + (First - '0'), Rest...>::value;
};
template <char... Chars>
struct ParseNumerator {
static constexpr int value = ParseNumeratorImpl<0, Chars...>::value;
};
template <int Value, bool, char...>
struct ParseDenominatorImpl {
static constexpr int value = Value;
};
template <int Value, bool RightOfDecimalPoint, char First, char... Rest>
struct ParseDenominatorImpl<Value, RightOfDecimalPoint, First, Rest...> {
static constexpr int value =
(First == '.' && sizeof...(Rest) > 0)
? ParseDenominatorImpl<1, true, Rest...>::value
: RightOfDecimalPoint
? ParseDenominatorImpl<Value * 10, true, Rest...>::value
: ParseDenominatorImpl<1, false, Rest...>::value;
};
template <char... Chars>
using ParseDenominator = ParseDenominatorImpl<1, false, Chars...>;
template <int Num, int Denom>
struct FloatingPointNumber {
static constexpr float float_value =
static_cast<float>(Num) / static_cast<float>(Denom);
static constexpr double double_value =
static_cast<double>(Num) / static_cast<double>(Denom);
constexpr operator double() { return double_value; }
};
template <int Num, int Denom>
FloatingPointNumber<-Num, Denom> operator-(FloatingPointNumber<Num, Denom>) {
return {};
}
template <char... Chars>
constexpr auto operator"" _c() {
return FloatingPointNumber<ParseNumerator<Chars...>::value,
ParseDenominator<Chars...>::value>{};
}
template <class Val>
int mul(double x) {
return Val::double_value * x;
}
template <class Val>
int mul(Val v, double x) {
return v * x;
}
int main() {
std::cout << mul<decltype(3.79_c)>(77) << "\n";
std::cout << mul(3.79_c, 77) << "\n";
return 0;
}
constexpr double make_double( int64_t v, int64_t man );
write a function that makes a double from a base and mantissa. This can represent every non-special double.
Then write:
template<int64_t v, int64_t man>
struct double_constant;
using the above make_double and various constexpr access methods.
You can even write base and exponent extracting constexpr functions I suspect. Add a macro to remove DRY, or use a variable.
Another approach is:
const double pi=3.14;//...
template<double const* v>
struct dval{
operator double()const{return *v;}
};
template<class X>
double mul(double d){
return d*X{};
}
double(*f)(double)=mul<dval<&pi>>;
which requires a variable to point to, but is less obtuse.
If you don't want to create type envelopes for each double/float constant used, then you can create a mapping between integer and double constants. Such mapping can be implemented e.g. as follows:
#include <string>
#include <sstream>
template<int index> double getValue()
{
std::stringstream ss("Not implemented for index ");
ss << index;
throw std::exception(ss.str());
}
template<> double getValue<0>() { return 3.6; }
template<> double getValue<1>() { return 7.77; }
template<int index> double multiply(double x)
{
return getValue<index>() * x;
}
Alternative options to implement the mapping are via a function which does switch-case on the input integer parameter and returns a float/double, or indexing to an array of constants, but both these alternatives would require constexpr for them to happen on compile-time, while some compilers still do not support constexpr: constexpr not compiling in VC2013
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