Runtime template arguments? - c++

I am writing an SI unit class that uses integer template arguments for the dimensions of the type. I am trying to write a power function, but I am running into the issue that the exponent is not necessarily known until runtime and therefore the template arguments are not either.
Some code is omitted in the examples
template <int m = 0, int s = 0, int kg = 0, int A = 0, int K = 0, int mol = 0, int cd = 0>
struct Dimension{
template <typename D, Ratio R> friend class Unit;
public:
real value;
template <int m2, int s2, int kg2, int A2, int K2, int mol2, int cd2>
constexpr Dimension<m+m2, s+s2, kg+kg2, A+A2, K+K2, mol+mol2, cd+cd2> operator*(Dimension<m2, s2, kg2, A2, K2, mol2, cd2> const & rhs) const {return value*rhs.value;}
//Power function here
};
The multiplication operator works because the result type depends on only template parameters.
None of the following work for the power operator because they all have the template argument depend on a runtime parameter.
constexpr auto operator^(int n) const {return Dimension<m*n, s*n, kg*n, A*n, K*n, mol*n, cd*n>{std::pow(value, n)};}
template <int N>
constexpr Dimension<m*N, s*N, kg*N, A*N, K*N, mol*N, cd*N> pow() const {return std::pow(value, N);}
constexpr auto operator^(int n) const {
if constexpr (n == 0) return Dimension<0, 0, 0, 0, 0, 0, 0>{std::pow(value, N)};
else if constexpr (n == 1) return Dimension<m*N, s*N, kg*N, A*N, K*N, mol*N, cd*N>{std::pow(value, N)};
else if constexpr (n == 2) return Dimension<m*2, s*2, kg*2, A*2, K*2, mol*2, cd*2>{std::pow(value, N)};
//...
// I can reasonably expect a range smaller than [-10, 10], but theoretically I should be able to have any n
}
Sorry if there are minor code mistakes, I have written them directly.
Are there any solutions that don't resort to macros that would let me solve this?

Related

Disambiguate recursive definition of template function

I am building a statically typed Matrix where all operations with matrices are typechecked. However, I am having issues when I want to do something that modifies the Matrix based on given number.
For instance, adding one column is trivial:
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
However, adding N columns is way harder. Since is impossible to typecheck with a function that has a branch where the return type is not the expected (even if the branch condition guarantees it) I can only think about a recursive approach:
template<int A, int B, int Z>
Matrix<A,B+1> addZCols(Matrix<A,B> m1) {
return addOneCol(m1);
}
template<int A, int B, int Z>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<A,B,Z-1>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
However, this is overloading addZCols in the return type, what is not allowed and leads to an error saying that calling addZCalls is ambiguous and cannot chose one of the 2 candidates. And what I want is that the version wiht B+1 is only called as the base case, so to speak, when Z=1.
Any idea about how to make this work or a different approach?
If I understand your requirement correctly, you could simply write the function template like this:
template<int A, int B, int Z = 1>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
and then use it like this:
Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<1,1,3>(Matrix<1,1>{});
By default, the 3rd parameter is 1, and so this function template can be used as addOneCol.
As #Evg points out, template parameters have the nice property that default arguments can appear in any order, so we could have the Z argument in the first position:
template<int Z = 1, int A, int B>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
This allows you to make the call more conveniently, like this:
Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
Since only Z needs to be specified, as A, and B can be deduced from the Matrix argument.
There may be a more efficient approach, but with the recursion solution that you proposed, SFINAE can be used to disambiguate the two versions of the template function.
#include <type_traits>
template <int A, int B>
struct Matrix {
constexpr int rows() const { return A; }
constexpr int cols() const { return B; }
int data;
};
template<int Z, int A, int B, std::enable_if_t<Z == 0, int> = 0>
Matrix<A, B> addZCols(Matrix<A,B> m1) {
return m1;
}
template<int Z, int A, int B, std::enable_if_t<Z != 0, int> = 0>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<Z-1, A, B>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
int main() {
Matrix<2, 2> m1;
auto m2 = addZCols<3>(m1);
static_assert(m2.rows() == 2, "check rows");
static_assert(m2.cols() == 5, "check cols");
return 0;
}
I have also offset the recursion limit by one for clarity and re-ordered the template parameters of addZCols to make it nicer to call, but it works just the same with your original signature.

How do I write a variadic template function in C++ where the parameter pack is not the last parameter?

I'm trying to use a variadic template function where the parameter pack is not the last parameter in the list. Note that there are two recursive calls--one dropping a parameter in front of the pack, the other call dropping a parameter after the pack.
My compiler appears to be: Apple LLVM version 8.1.0 (clang-802.0.42)
All the int's below will be a new T template parameter if I can get this working.
There's no point in using ... if the call site for Blender can't be clean. I could just expand several overloads of Blender myself in that case. I'd really rather not resort to this. I hope I'm just missing something.
int Blender( double t, int i)
{
return i;
}
template <typename ...Args>
int Blender( double t, int first, Args... more, int last)
{
return (1-t)*Blender(t, first, more...) + t*Blender(t, more..., last);
}
static void tryit()
{
Blender(.5, 23, 42, 89); //doesn't compile
}
I propose another solution, really different from the code in the question, that I think is a lot more efficient (creation on only one std::array; blender obtained by template index sequence)
#include <array>
#include <utility>
#include <iostream>
template <typename T, std::size_t I0>
int blenderH (double t, T const & arr, std::index_sequence<I0> const &)
{ return arr[I0]; }
template <typename T, std::size_t I0, std::size_t ... Is>
auto blenderH (double t, T const & arr,
std::index_sequence<I0, Is...> const &)
-> std::enable_if_t<0U != sizeof...(Is), int>
{ return (1-t) * blenderH(t, arr, std::index_sequence<(Is-1U)...>{})
+ t * blenderH(t, arr, std::index_sequence<Is...>{}); }
template <typename ... Args>
int blender (double t, Args ... as)
{
static constexpr auto size = sizeof...(Args);
return blenderH(t, std::array<int, size>{ { as... } },
std::make_index_sequence<size>{});
}
int main()
{ std::cout << blender(.3, 23, 42, 89) << std::endl; }
Unfortunately also this solution works (std::index_sequence and std::make_index_sequence) starting from C++14.
-- EDIT --
Caleth say.
Some explanation of what is going on here would help. I am confused by the lack of I0 in the body of the second overload.
I try an explanation.
Suppose is called the recursive version of BlenderH() (the second overload) with a list of index in the std::index_sequence value. Say 5, 6, 7 and 8; so I0 is 5 and Is... is 6, 7, 8.
We have to recursive call blenderH() with indexes 5, 6, 7 first and with 6, 7, 8 next.
We can avoid to use I0 (5) because
5, 6, 7 is obtained from 6, 7, 8 reducing by 1 every value (so the std::index_sequence<(Is-1U)...> for the first recursive call)
and 6, 7, 8 is Is... without modifications (so the std::index_sequence<Is...> in the second one.
From the practical point of view, I0 is declared only to be discarded; ther is no need to use it.
template<std::size_t I>
using count = std::integral_constant<std::size_t, I>;
namespace details {
template<class...Args, std::size_t N,
typename std::enable_if<sizeof...(Args)==N, bool>::type = true
>
int Blender( count<N> drop, double t, int i, Args...args ) {
return i;
}
template<class...Args, std::size_t N,
typename std::enable_if<sizeof...(Args)!=N, bool>::type = true
>
int Blender( count<N> drop, double t, int i, Args...args ) {
return (1-t)*Blender( count<N+1>{}, t, i, args... ) + t*Blender( count<N>{}, t, args... );
}
}
template <typename ...Args>
int Blender( double t, int first, Args... more)
{
return details::Blender( count<0>{}, first, more... );
}
static void tryit()
{
Blender(.5, 23, 42, 89); //doesn't compile
}
here count<N> counts the number of arguments at the end to ignore.
The two details overload cover the case where N is equal to the number of arguments in the pack (and hence we have 1 argument left), and when it is not. They are dispatched to using SFINAE.
This is actually really easy once you realize that the limitation is in the type pack deduction and not in the function call. We just need a way to use the type pack we can deduce and pass it explicitly avoiding deduction at the function that needs to pull off the last parameter:
int Blender( double t, int i)
{
return i;
}
template <typename ...Args>
int Blender( double t, int first, Args... more);
template <typename ...Args>
int BlenderWithoutLast( double t, Args... more, int last)
{
return Blender(t, more...);
}
template <typename ...Args>
int Blender( double t, int first, Args... more)
{
return (1-t)*BlenderWithoutLast<Args...>(t, first, more...) + t*Blender(t, more...);
// all the magic happens here ^^^^^
}
and now your test case compiles and runs
#include <iostream>
int main()
{
std::cout << Blender(.5, 23, 42, 89);
}
For me this works with clang and --std=c++11

Simplify variadic template: Remove some specializations

I found a template to calculate the binomial coefficient, which I happily used for function generation. The advantage is that I use this template for compile time Bernstein polynomial generation instead of using the derived polynomials (just 5 very simple ones).
I initially thought the code would become easier by doing so because the generation of the five random functions now obvious. Unfortunately, the code below is hard to read for someone not used to templates. Is there a way to get rid of at least some of the template specializations?
// Template functions to estimate the binominal coefficient
template<uint8_t n, uint8_t k>
struct binomial {
static constexpr int value = (binomial<n - 1, k - 1>::value + binomial<n - 1, k>::value);
};
template<>
struct binomial<0, 0> {
static constexpr int value = 1;
};
template<uint8_t n>
struct binomial<n, 0> {
static constexpr int value = 1;
};
template<uint8_t n>
struct binomial<n, n> {
static constexpr int value = 1;
};
You might probably use constexpr functions. Here is C++11-friendly version:
constexpr int factorial(int n)
{
return (n == 1) ? 1 : n * factorial(n - 1);
}
constexpr int bin_coeff(int n, int k)
{
return factorial(n) / factorial(n - k) / factorial(k);
}
EXAMPLE

C++ array as template parameter

I want to write a simple polynomial class that can take an array of coefficients and expand it into a function a compile time so I don't need to loop over the coefficients at run time. I want to do something like this:
template <PARAM_TYPE, PARAMS>
class P {
public:
PARAM_TYPE eval(PARAM_TYPE p){
//Does PARAMS[0] * pow(p, PARAMS.length() -1) + ... + PARAMS[N-1]
}
}
Sample call
P<double,{2,4,3}> quadratic;
quadratic.eval(5); //returns 73
I don't want to be doing the loop since that will take time. Ideally I want to be able to form the expression above at compile time. Is this possible? Thanks
Here is an example of doing what you want. The compiler is finicky about whether or not it optimizes away all the code into constants depending on the usage I noticed and which compiler you use.
test here
#include <type_traits>
template<class T, unsigned Exponent>
inline constexpr typename std::enable_if<Exponent == 0, T>::type
pow2(const T base)
{
return 1;
}
template<class T, unsigned Exponent>
inline constexpr typename std::enable_if<Exponent % 2 != 0, T>::type
pow2(const T base)
{
return base * pow2<T, (Exponent-1)/2>(base) * pow2<T, (Exponent-1)/2>(base);
}
template<class T, unsigned Exponent>
inline constexpr typename std::enable_if<Exponent != 0 && Exponent % 2 == 0, T>::type
pow2(const T base)
{
return pow2<T, Exponent / 2>(base) * pow2<T, Exponent / 2>(base);
}
template<typename ParamType>
inline constexpr ParamType polynomial(const ParamType&, const ParamType& c0)
{
return c0;
}
template<typename ParamType, typename Coeff0, typename ...Coeffs>
inline constexpr ParamType polynomial(const ParamType& x, const Coeff0& c0, const Coeffs& ...cs)
{
return (static_cast<ParamType>(c0) * pow2<ParamType, sizeof...(cs)>(x)) + polynomial(x, static_cast<ParamType>(cs)...);
}
unsigned run(unsigned x)
{
return polynomial(x, 2, 4, 3);
}
double run(double x)
{
return polynomial(x, 2, 4, 3);
}
unsigned const_unsigned()
{
static const unsigned value = polynomial(5, 2, 4, 3);
return value;
}
double const_double()
{
static const double value = polynomial(5, 2, 4, 3);
return value;
}
EDIT: I have updated the code to a use a tweaked version of pow2<>() that aggressively performs calculations at compile time. This version optimizes so well at -O2 that it actually surprised me. You can see the generated assembly for the full program using the button above the code. If all arguments are constant, the compiler will generate the entire constant value at compile time. If the first argument is runtime-dependent, it generates very tight code for it still.
(Thanks to #dyp on this question for the inspiration to pow)
To evaluate a polynom, a good algorithm is Horner (See https://en.wikipedia.org/wiki/Horner%27s_method). The main idea is to compute the polynom recursively. Let's a polynom P of order n with coefficient ai. It is easy to see that the sequence Pk = Pk-1*x0 + an-k with P0 = an, that P(x0) = Pn.
So let's implement this algorithm using constexpr function:
template<class T>
constexpr double horner(double x, T an) { return an; }
template<class... T, class U = T>
constexpr double horner(double x, U an, T... a) { return horner(x, a...) * x + an; }
std::cout << horner(5., 1, 2, 1) << std::endl;
//test if the invocation of the constexpr function takes the constant expression branch
std::cout << noexcept(horner(5., 1, 2, 1)) << std::endl;
As you see, it is really easy to implement the evaluation of a polynom with constexpr functions using the recursive formula.

Programmatic initialization of a long array at compile or initialization time

Here is a code snippet illustrating my question:
const float D = 0.1F;
const float A[4] = {sin(0*D), sin(1*D), sin(2*D), sin(3*D)};
Imagine that global array A is much longer and you don't want to do all of this repetitive typing. Is there a shorter way to initialize array A at compile or initialization time, i.e. without having to write initialization function and call it somewhere in my program?
You could initialize A during dynamic initialization time as follows:
const float *init_a(float x_)
{
static float data[4];
for(unsigned i=0; i<4; ++i)
data[i]=sin(i*x_);
return data;
}
const float D=0.1f;
const float *A=init_a(D);
You may use code generator to generate initialization code. That is, write program that will write your initialization code for you. You may actually calculate values at generation-time.
Remember that C++ allows placing , after last element. It's also isn't necessary to specify array size. These two things should ease writing of generator.
This simple python code should work well:
from math import sin
print('const float A[', N, '] = {')
for i in range(N):
print('\t', sin(i*D), ',', sep='')
print('};')
Ok I just realized this doesn't actually answer the question, because it specifies "without having to write initialization function and call it somewhere in my program?" But I can't think of a convenient alternative.
template<size_t N>
std::array<float, N> GetLookupTable(float d)
{
std::array<float, N> table;
// .. populate table here
return table;
}
// a global somewhere
(static?) const auto Table_10x5 = GetLookupTable<10>(5.0f);
This first part is obsolete in C++14, but not long:
template<unsigned...>struct indexes { using type=indexes; };
template<unsigned Max, unsigned...Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Max>using make_indexes_t=typename make_indexes<Max>::type;
this is some template meta programming that lets us create and pass around bundles of indexes.
Then some code to generate the array:
namespace details {
template<std::size_t N, unsigned...Is>
std::array<float, N> poly_sin(float src, indexes<Is...>) {
return { (Is*sin(src))... };
}
}
template<std::size_t N>
std::array<float, N> poly_sin(float src) {
return details::poly_sin<N>( src, make_indexes_t<N>{} );
}
The first method takes indexes<Is...> and we plan that Is... is 0, 1, 2, ..., N-1. It then expands the parameter pack into a std::array of the right size.
make_indexes_t<N>{} expands (at compile time) to indexes<0, 1, 2, ..., N-1>{}, which is then passed to details::poly_sin, which then can deduce the Is... and use them within itself.
And point of use:
const float D = 0.1F;
const auto A = poly_sin<4>(D);
if you had a constexpr sin function, you could even make poly_sin a constexpr function and have it basically guaranteed to be evaluated at compile time.
If this is the case, make D constexpr and same with the two poly_sin functions.
As written, this occurs at dynamic initialization time.
While it appears that the array is copied twice, RVO elision means that any decent compiler will directly construct it in A.
If you want to be able to do this in general, first start with the above indexes code. Then add this:
template<class Sig>using result_of_t=typename std::result_of<Sig>::type;
namespace details {
template<std::size_t N, class F, unsigned... Is>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f, indexes<Is...> ) {
return { f( Is )... };
}
}
template<std::size_t N, class F>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f ) {
return details::make_array( std::forward<F>(f), make_indexes_t<N>{} );
}
const auto A = make_array<4>( [](unsigned i){ return float(i*sin(D)); } );
which uses a lambda to pass in the code that is repeated to build the array. Sadly, lambdas are not by default constexpr so you cannot do it at compile time.
You could either use boost.preprocessor and in particular the BOOST_PP_ENUM macro, like the example below:
#include <iostream>
#include <cmath>
#include <boost/preprocessor/repetition/enum.hpp>
#define SIZE 4
#define D 0.1
#define ORDER(z, n, text) std::sin(n * D)
double const A[SIZE] = { BOOST_PP_ENUM(SIZE, ORDER, ~) };
int main() {
for(auto i : A) std::cout << i << std::endl;
}
Or, you could use std::array instead of raw arrays, and via use of template meta-programming to generate a std::array at compile time. like the example below:
template<typename T, typename F, int SIZE, int... N>
constexpr std::array<T, SIZE>
genarray(F f) {
return std::array<T, SIZE>{{ f(N)... }};
}
template<typename T, typename F, int SIZE, int...> struct recursive_gen;
template<typename T, typename F, int SIZE, int... Args>
struct recursive_gen<T, F, SIZE, 0, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return genarray<T, F, SIZE, 0, Args...>(f);
}
};
template<typename T, typename F, int SIZE, int N, int... Args>
struct recursive_gen<T, F, SIZE, N, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, N - 1, N, Args...>::generate(f);
}
};
template<typename T, int SIZE>
struct array_generator {
template<typename F>
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, SIZE - 1>::generate(f);
}
};
std::array<double, 4> const A = array_generator<double, 4>::generate([](int i) { return std::sin(0.1 * i);});
std::array<double, 4> const B = array_generator<double, 4>::generate([](int i) { return std::cos(0.1 * i);});
constexpr int fun(int i) { return 2 * i; }
constexpr std::array<int, 4> const C = array_generator<int, 4>::generate(fun); // generation during compile time
LIVE DEMO
Note however, that in order for generation to take place at compile time input function in array_generator must be constexpr. This is not the case for trigonometric functions (i.e., they are not constexpr). Thus initialization of arrays A and B will take place at initialization time, whereas generation of array C will take place at compile time.
Imagine that global array A is much longer and you don't want to do all of this repetitive typing. Is there a shorter way to initialize array A at compile or initialization time
Create a generator and pass it through std::generate_n() (or plain std::generate()).
#include <algorithm>
#include <array>
#include <cmath>
template <typename Value_t>
struct SinGenerator{
SinGenerator(std::size_t start = 0, Value_t counter_scalar = 1)
: index{start},
scalar{counter_scalar} {
}
Value_t operator()() {
return sin(index++ * scalar);
}
std::size_t index;
Value_t scalar;
};
template <typename Value_t, std::size_t Size>
std::array<Value_t, Size> init_table(const std::size_t start,
const Value_t counter_scalar) {
std::array<Value_t, Size> arr;
SinGenerator<Value_t> gen(start, counter_scalar);
std::generate(arr.begin(), arr.end(), gen);
return arr;
}
const auto kSinTable(init_table<float, 10>(0, 0.1f));
In case you A array will always stays the same and is very big, you can always write a short script, which calculates every value in array and output could be used in source code to have static initialization.
In case formula is simple, even MS Excel could be used to generate that kind of static initialization data.