Trying to sum two compile time tuple integer sequences - c++

If you're keeping track of my question history, I'm updating a dimensional analysis library for the sake of ditching a nightmare of macros and learning C++11, variadic templates, and meta programming and functional programming paradigms. For the life of me, this stuff is still magic.
Anyway, I have tuples of exponent constants that define physical units.
template<int... I>
using make_dimension = std::tuple<std::ratio<I>...>;
using scalar_dimension = make_dimension<0, 0, 0, 0, 0, 0, 0>;
using length_dimension = make_dimension<1, 0, 0, 0, 0, 0, 0>;
using time_dimension = make_dimension<0, 0, 1, 0, 0, 0, 0>;
This is (part) of a library that models the SI units. You can only multiply unlike units, you can additionally add like units and scalars. These libraries are dandy in that they cause compile time errors if you mix units inappropriately. There are >400 units and most of them are defined in terms of other units. When multiplying units, exponents are added, and when dividing units, exponents are subtracted. So to define velocity, I would love a means of expressing:
using velocity_dimension = divide_dimensions<length_dimension, time_dimension>;
And that should be functionally equivalent to writing:
using velocity_dimension = make_dimension<1, 0, -1, 0, 0, 0, 0>;
I've been Googling, but I just don't know the terminology to land some hits. The closest I've found was a for_each that applies a function to elements of a tuple at runtime... And it's kind of blowing my mind, so I can't quite figure out how to turn it into a compile time iteration over the elements. 'make_dimension' above was explained to me a moment ago and it blew my mind, but I recovered. I'm kind of bugged asking for a handout, so does anyone have any good resources for learning this stuff? I'm having a hard time believing I'm the only one remotely interested in doing this.

#dyp's solution in the comments uses a recursively instantiated template. While that's one of the most general techniques for variadic templates, in this case recursion is probably overkill, as the entire set of transformations can be performed in a single pack expansion that expands two parameter packs simultaneously:
template<template<class, class> class, class, class>
struct tuple_transform; // undefined
template<template<class, class> class Transform, class...Ts, class...Vs>
struct tuple_transform<Transform, std::tuple<Ts...>, std::tuple<Vs...>> {
using type = std::tuple<Transform<Ts, Vs>...>;
};
template<class T, class U>
using divide_dimensions = typename tuple_transform<std::ratio_subtract, T, U>::type;
Note that the above assumes that Transform<T, U> is an alias for the desired resulting type. This matches the behavior of ratio_add etc. - they are alias templates for the resulting std::ratio, so typename ratio_add<...>::type is not necessary.
Demo.

While T.C.s answer is correct you can simply take std::integer_sequence (which is C++ 14 but can be simply implemented) instead of ratio and tuple which (in my opinion) don't really fit und use a constexpr functor for manipulation.
Now your code should look like the following (which I didn't try to compile):
template<int... I>
using make_dimension = std::integer_sequence<int, I...>;
template<class Functor, class Dim1, class Dim2>
struct transfrom;
template<class Functor, int... Dims1, int... Dims2>
struct transform<
Functor,
std::integer_sequence<int, Dims1...>,
std::integer_sequence<int, Dims2...>
> {
static_assert(sizeof...(Dims1)==sizeof...(Dims2), "wrong dimensions");
static constexpr Functor f;
using type=std::integer_sequence<int, f(Dims1,Dims2)...>;
};
struct add {
constexpr int operator()(int l, int r) const { return l+r; }
};
struct sub {
constexpr int operator()(int l, int r) const { return l-r; }
};
template<class T, class U>
using divide_dimensions = typename transform<sub, T, U>::type;

I don't have enough info, but it looks like (1,0,-2,0,0,0,0) would be what you would need for acceleration. The 1 represents meters and the - 2 would represent division by seconds squared just as a negative exponent does in math.

Related

Automatically generate all template instantiations [duplicate]

Explicit template instantiation is very useful when creating libraries. Suppose I have a template with an int paramater:
template <int i> struct S { ... };
To perform explicit template instantiation, the grammar is something like
template struct S<1>;
However, I can only instantiate one instance using one line in this way. What I want to do is to define a range of template in an elegant way. For example, consider the wrong code that can not be compiled:
#define MIN_I 1
#define MAX_I 16
for (int i = MIN_I; i <= MAX_I; i++) // i should be a constant
template struct S<i>;
In this way, when MAX_I is changed, the modification is very simple. Can I achieve this goal? If it is possible, is there an easy way to do such thing? Thank you!
Also, this question can be generalized to a more general setting. For example, I can take 1,2,4,8,16,32,64,128,256 or some predefined sequence.
The reason that I create a template library is not easy to say. In short, I will create a CUDA library that runs on GPU (which is compiled by nvcc compiler), and is called by a standard c++ program which is compiled by gcc.
Let's start with a slight shift in perspective. The goal is to instantiate certain instances of a given template. Note that I dropped the word "explicit" – while there will be an explicit instantiation, it need not be of the template in question. Rather, I would explicitly instantiate a helper template that will implicitly instantiate the desired template.
The helper template will use a parameter pack to accommodate an arbitrary number of arguments. This would be reasonably straight-forward if the goal was to simply list numbers. However, there is also a desire to be able to specify a min and max. To handle this case, I'll support std::integer_sequence as a template argument, which I'll handle via partial specialization.
// Start with a template that will not be defined; we will define only a
// specialization of this.
// The `C` parameter allows this to be applied to more templates than just `S`.
// The other parameters will make more sense for the specialization.
template<template<int> typename C, int ADD, class T> struct force_instantiation_impl;
// Partially specializing the template allows access to the numbers comprising the
// `integer_sequence` parameter.
// The ADD parameter will be added to each number in the sequence (will be helpful later).
template<template<int> typename C, int ADD, int... Ints>
struct force_instantiation_impl<C, ADD, std::integer_sequence<int, Ints...>> {
// Implicitly instantiate the desired templates.
std::tuple<C<ADD + Ints>...> unused;
};
Here, parameter pack expansion is used to iterate over all desired template arguments. This plays the role given to the loop in the "wrong code" of the question. Of course, we still have to get the indices for a given minimum and maximum.
For convenience, I would provide another layer of helper templates, an "interface" layer, if you will. The first interface helper allows specifying just the template, the minimum, and the maximum. Instantiating this helper will cause the desired templates to be instantiated.
// Instantiates C<I> for I ranging from MIN to MAX.
// MAX must be at least as large as MIN.
template<template<int> typename C, int MIN, int MAX>
struct force_instantiation_range {
// Check the assumption.
static_assert(MIN <= MAX);
// Make an integer sequence from 0 to (MAX-MIN) for the template argument.
// When MIN is added to each element, the sequence will go from MIN to MAX.
force_instantiation_impl<C, MIN, std::make_integer_sequence<int, MAX-MIN+1>> unused;
};
The other interface helper allows simply listing the desired arguments. To some extent, the purpose of this helper is to hide the complexities introduced by supporting a range of arguments. (If it were not for that support, the parameters to this template could have been the parameters to force_instantiation_impl.)
// Instantiates C<I> for the given I's.
template<template<int> typename C, int... Ints>
struct force_instantiation_list {
force_instantiation_impl<C, 0, std::integer_sequence<int, Ints...>> unused;
};
And that's it. It might look like a lot of code because of the comments, but it's actually reasonably short. There are three struct template definitions, each with a single member. To put this to use, explicitly instantiate one of the interface helpers.
// Forgive me, I'm changing the pre-processor directives to type-safe constants.
constexpr int MIN_I = 1;
constexpr int MAX_I = 16;
template struct force_instantiation_range<S, MIN_I, MAX_I>;
Equivalently, the arguments could be explicitly listed.
template struct force_instantiation_list<S, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16>;
Admittedly, I did shift the question a bit. If you really need explicit instantiations directly of your template, then this approach will not work. If that is the case, you might have to rely on the pre-processor, which can be a nightmare to get right. Fortunately, Boost.Preprocessor has already taken care of the most painful of the details. I'd take advantage of that.
With Boost.Preprocessor it could be done literally in two lines.
//temp.h
#pragma once
//Let's declare a template with a member function
template<int N>
struct MyStruct {
void About() const;
};
//temp.cpp
#include "temp.h"
#include <iostream>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
//Let's define the template member function outside the header. Normally it would not link
template<int N>
void MyStruct<N>::About() const {
std::cout << N << std::endl;
}
//All the trick is in the next two lines
#define INSTANT(z, n, Struct) template struct Struct<n>;
BOOST_PP_REPEAT_FROM_TO(1, 16, INSTANT, MyStruct);
//main.cpp
#include "temp.h"
int main() {
MyStruct<2>().About();
MyStruct<5>().About();
MyStruct<12>().About();
return 0;
}
All is compiling, linking and running correctly. It looks like if you want to become a full-fledged metaprogrammer, you should master preprocessor techniques as well.
this question can be generalized to a more general setting. For example, i can take 1,2,4,8,16,32,64,128,256 or some predefined sequence.
This can also be easily:
template <int i> struct S { };
//version that will do the real work
template<template<int>typename Functor, int J, int... I> void f()
{
int j = (Functor<J>{},1);
int i = (Functor<I>{},...,1);
}
int main()
{
f<S, 1, 3, 5, 76, 4, 5>();
}
Working demo.
What I want to do is to define a range of template in an elegant way.
Here is another way(more straighforward) of doing this using templates in both C++11 as well as C++20.
C++20 Version
Here we make use of requires.
template <int i> struct S { };
//for ending recursion
template<std::size_t min, std::size_t max, template<int>typename > void f() requires(min==max+1){}
//version that will do the real work
template<std::size_t min, std::size_t max, template<int>typename Functor> void f() requires(min!=max+1)
{
int i = (Functor<min>{},1);
f<min+1, max, Functor>();
}
int main()
{
f<1,16, S>();
}
Working demo c++20
It is trivial to make this work with C++11. See Working demo C++11. This C++11 version uses SFINAE

Partial template argument deduction or workaround for std::array?

C++17 allows us to have std::array's template arguments deduced. E.g., I can write
std::array ints = { 1, 2, 3 };
and ints will be of type std::array<int, 3>.
My question is: what if I wanted to specify only the type argument of the array but have the size of the array automatically determined?
The following does not work since it seems like all template arguments have to be specified:
std::array<size_t> sizes = { 1, 2, 3 };
My compiler complains and says: 'std::array': too few template arguments.
Is it possible to have the size of the array determined automatically by template argument deduction? If not, is it possible to create an array by only specifying its type but not its size?
As far as I know, this cannot be done. But a helper method does the trick:
template<typename Type, typename ... T>
constexpr auto makeArray(T&&... t) -> std::array<Type, sizeof...(T)>
{
return {{std::forward<T>(t)...}};
}
Usage example:
const auto container = makeArray<double>(-5.0, 0.0, 5.0, 10.0);
If, I might be so bold as to expand on the Benjamin's answer. Conceptually one does not need always to be explicit about the result type.
template<
typename ... T,
typename CT = std::common_type_t< T... >
>
constexpr auto make_array(T&& ... t)
-> std::array< CT , sizeof...(T)>
{
return { { static_cast<CT>( std::forward<T>(t) ) ...} };
}
Slightly simpler usage
constexpr auto std_arr = make_array(-5.0, 0.0, 5.0, 10.0);
The issue here might be, we are not exactly certain, what type of the std::array we will get. Provided we do care about it.
const auto std_arr = make_array(-5.0, 0, 5.0, 10.0, 42.13f );
Over "here", using MSVC, the latest, I get std array of doubles. If one's bed time reading is ISO C++ standard doc, the one might be sure what type will come out of std::common_type from the tool chain in use.
For the rest of us, literal suffixes will help
constexpr auto sizes = make_array( 1UL, 2UL, 3UL );
But why stop with numbers? One can collect quickly, into an array, instances from the same hierarchy. Not caring about the result type.
{
const auto exceptions = make_array(
std::exception{"SE"},
std::runtime_error{"RE"},
std::logic_error{"LE"} );
}
A bit useless but somewhat weird and wonderful. One thing thou remember: this is compile time situation. Thus, I might prefer:
constexpr auto sizes = std::array{ 1UL, 2UL, 3UL } ;
To answer the OP's question directly.
There is also C++20 std::to_array. For the exact result type and for a bit more comfortable usage:
constexpr auto sizes = std::to_array<size_t>({ 0, 1, 3 });
Enjoy ...

Compile-Time Creation of Array of Templated Objects in High Level Synthesis

I'm trying to accomplish this with HLS, not with "normal" C++, so most libraries (STL, boost, etc.) won't work as they can't be synthesized (manual memory management is not allowed). I think this should be possible with template metaprogramming, but I'm a little stuck.
I want to create an array of shift registers, each with a variable depth. I have N inputs, and I want to create N shift registers, with depths 1 to N, where N is known at compile time. My shift register class basically looks like
template<int DEPTH>
class shift_register{
int registers[DEPTH];
...
};
I tried following this and adapting it: Programmatically create static arrays at compile time in C++ , however, the issue is with the last line. Each templated shift register is going to be a different type, and so can't be put together in an array. But I do need an array, as there wouldn't be a way to access each shift register.
Any help would be appreciated!
Just to clarify, my problem was the following: generate N shift_registers, templated from 1 to N, where N is a compile time constant.
For example, if I had N=4, I could easily write this as:
shift_register<1> sr1;
shift_register<2> sr2;
shift_register<3> sr3;
shift_register<4> sr4;
But this wouldn't be easy to change, if I wanted a different value for N in the future.
I ended up using the preprocessor and took the solution from here: How do I write a recursive for-loop "repeat" macro to generate C code with the CPP preprocessor?
I used the macros from that solution like this:
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define BODY(i) shift_register<i> CAT(sr,i)
REPEAT_ADD_ONE(BODY, N, 1);
And then something similar to that in order to access the shift registers, in a sort of array fashion.
This let me achieve the compile time generation that I was looking for, and get the array type access I needed.
Your question was somewhat difficult to understand but I'll do my best...
template <typename ... Args>
constexpr auto make_array(Args && ... pArgs)
{
using type = std::common_type_t<std::decay_t<Args>...>;
return std::array<type, sizeof...(Args)>{ (type)pArgs ... };
}
Then use it like this:
auto constexpr var_array_of_arrays = std::make_tuple
(
make_array(1, 2, 3, 3),
make_array(2, 3, 4),
make_array(1, 2, 3 ,4 ,3, 5)
);
To get the M'th element you access it like this, n has to actually be a compile-time constant:
std::get<M>(var_array_of_arrays);
To access the Nth element in the Mth array:
auto constexpr value = std::get<M>(var_array_of_arrays)[N]
An to improve the interface:
template <size_t M, size_t N, typename T >
constexpr decltype(auto) get_element(T && pInput)
{
return std::get<M>(std::forward<T>(pInput))[N];
}
Used like this:
auto constexpr element0_1 = get_element<0, 1>(var_array_of_arrays);
This will allow you to use an array of variable length arrays, or atleast something that behaves like that and is identical to that in memory.
A full example is here:
Online compiler
Whenever I hear "compile time number sequence" I think std::index_sequence
namespace detail {
template <typename>
struct shift_registers;
template <std::size_t ... Is> // 0, 1, ... N-1
struct shift_registers<std::index_sequence<Is...> > {
using type = std::tuple<shift_register<Is + 1>...>;
};
template <typename T>
using shift_registers_t = typename shift_registers<T>::type
}
template <std::size_t N>
using shift_registers = detail::shift_registers_t<std::make_index_sequence<N>>;

Change member-typedef depending on template parameter?

I have this problem here that I can’t figure out how to solve. I want a template class that takes an integer as template parameter and sets the template parameters for another class accordingly:
template <int T>
class Solver
{
public:
#if T <= 24
typedef MyMatrix<float> Matrix;
#else if T <= 53
typedef MyMatrix<double> Matrix;
#else
typedef MyMatrix<mpreal> Matrix;
#endif
Matrix create();
};
And then calling it like this:
Solver<53>::Matrix m = Solver<53>::create();
How can I do something like this? At the moment with the code above, the compiler complaints that it doesn't know "Matrix", so I'm not sure if you can use the preprocessor on template parameters.
INTRODUCTION
Since you'd like S<N>::Matrix to yield a different type depending on the N passed, you will need to use some sort of meta template programming. The question is currently tagged with preprocessor, and the snippet explicitly tries to use it; but that is of little to no use in this case.
When the code is being preprocessed N is nothing more than a name, it hasn't got a value; yet.
Solution
The description mentiones if, if ... else, and else; and we are dealing with types.. looking through <type_traits> it seems like std::conditional would be a perfect match!
std::conditional<condition, type-if-true, type-if-false>::type;
Note: Depending on whether the expression found in condition yields true, or false, ::type will be a typedef for either type-if-true, or type-if-false.
Let's write a sample implementation:
#include <type_traits>
template <int N>
class Solver
{
public:
typedef typename std::conditional<
/* */ (N <= 24),
/* y? */ MyMatrix<float>,
/* n? */ typename std::conditional<(N <= 53), MyMatrix<double>, MyMatrix<mpreal>>::type
>::type matrix_type;
...
};
int main () {
Solver<53>::matrix_type a; // Matrix<double>
Solver<10>::matrix_type b; // Matrix<float>
Solver<99>::matrix_type c; // Matrix<mpreal>
}
You can use std::conditional for this, although whether you should be doing this in the first place is another kettle of fish:
template<int T>
class Solver
{
std::conditional_t<
T <= 24,
MyMatrix<float>,
std::conditional_t<
T <= 53,
MyMatrix<double>,
MyMatrix<mpreal>
>
> Matrix;
};
You'll need to use std::conditional and ::type instead of conditional_t if your compiler doesn't support it.
No, you can't use the preprocessor on template parameters.
The preprocessor is just doing very simple string processing on your input source. It has no glue about types and I think it is run as the very first step while first processing the file and collecting all the includes. Templates are something the compiler itself takes care of. At this point the preprocessor has finished already.
A similar question has been asked here:
Use a template parameter in a preprocessor directive?

map/fold operators (in c++)

I am writing library which can do map/fold operations on ranges. I need to do these with operators. I am not very familiar with functional programming and I've tentatively selected * for map and || for fold. So to find (brute force algorithm) maximum of cos(x) in interval: 8 < x < 9:
double maximum = ro::range(8, 9, 0.01) * std::cos || std::max;
In above, ro::range can be replaced with any STL container.
I don't want to be different if there is any convention for map/fold operators. My question is: is there a math notation or does any language uses operators for map/fold?
** EDIT **
For those who asked, below is small demo of what RO currently can do. scc is small utility which can evaluate C++ snippets.
// Can print ranges, container, tuples, etc directly (vint is vector<int>) :
scc 'vint V{1,2,3}; V'
{1,2,3}
// Classic pipe. Alogorithms are from std::
scc 'vint{3,1,2,3} | sort | unique | reverse'
{3, 2, 1}
// Assign 42 to [2..5)
scc 'vint V=range(0,9); range(V/2, V/5) = 42; V'
{0, 1, 42, 42, 42, 5, 6, 7, 8, 9}
// concatenate vector of strings ('add' is shotcut for std::plus<T>()):
scc 'vstr V{"aaa", "bb", "cccc"}; V || add'
aaabbcccc
// Total length of strings in vector of strings
scc 'vstr V{"aaa", "bb", "cccc"}; V * size || (_1+_2)'
9
// Assign to c-string, then append `"XYZ"` and then remove `"bc"` substring :
scc 'char s[99]; range(s) = "abc"; (range(s) << "XYZ") - "bc"'
aXYZ
// Remove non alpha-num characters and convert to upper case
scc '(range("abc-123, xyz/") | isalnum) * toupper'
ABC123XYZ
// Hide phone number:
scc "str S=\"John Q Public (650)1234567\"; S|isdigit='X'; S"
John Q Public (XXX)XXXXXXX
This is really more a comment than a true answer, but it's too long to fit in a comment.
At least if my memory for the terminology serves correctly, map is essentially std::transform, and fold is std::accumulate. Assuming that's correct, I think trying to write your own would be ill-advised at best.
If you want to use map/fold style semantics, you could do something like this:
std::transform(std::begin(sto), std::end(sto), ::cos);
double maximum = *std::max_element(std::begin(sto), std::end(sto));
Although std::accumulate is more like a general-purpose fold, std::max_element is basically a fold(..., max); If you prefer a single operation, you could do something like:
double maximum = *(std::max_element(std::begin(sto), std::end(sto),
[](double a, double b) { return cos(a) < cos(b); });
I urge you to reconsider overloading operators for this purpose. Either example I've given above should be clear to almost any reasonable C++ programmer. The example you've given will be utterly opaque to most.
On a more general level, I'd urge extreme caution when overloading operators. Operator overloading is great when used correctly -- being able to overload operators for things like arbitrary precision integers, matrices, complex numbers, etc., renders code using those types much more readable and understandable than code without overloaded operators.
Unfortunately, when you use operators in unexpected ways, precisely the opposite is true -- and these uses are certainly extremely unexpected -- in fact, well into the range of "quite surprising". There might be question (but at least a little justification) if these operators were well understood in specific areas, but contrary to other uses in C++. In this case, however, you seem to be inventing a notation "out of whole cloth" -- I'm not aware of anybody using any operator C++ supports overloading to mean either fold or map (nor anything visually similar or analogous in any other way). In short, using overloading this way is a poor and unjustified idea.
Of the languages I know, there is no standard way for folding. Scala uses operators /: and :\ as well as metthod names, Lisp has reduce, Haskell has foldl.
map on the other hand is more common to find simply as map in all the languages I know.
Below is an implementation of fold in quasi-human-readable infix C++ syntax. Note that the code is not very robust and only serves to demonstrate the point. It is made to support the more usual 3-argument fold operators (the range, the binary operation, and the neutral element).
This is easily the funnies way to abuse (have you just said "rape"?) operator overloading, and one of the best ways to shoot yourself in the foot with a 900 pound artillery shell.
enum { fold } fold_t;
template <typename Op>
struct fold_intermediate_1
{
Op op;
fold_intermediate_1 (Op op) : op(op) {}
};
template <typename Cont, typename Op, bool>
struct fold_intermediate_2
{
const Cont& cont;
Op op;
fold_intermediate_2 (const Cont& cont, Op op) : cont(cont), op(op) {}
};
template <typename Op>
fold_intermediate_1<Op> operator/(fold_t, Op op)
{
return fold_intermediate_1<Op>(op);
}
template <typename Cont, typename Op>
fold_intermediate_2<Cont, Op, true> operator<(const Cont& cont, fold_intermediate_1<Op> f)
{
return fold_intermediate_2<Cont, Op, true>(cont, f.op);
}
template <typename Cont, typename Op, typename Init>
Init operator< (fold_intermediate_2<Cont, Op, true> f, Init init)
{
return foldl_func(f.op, init, std::begin(f.cont), std::end(f.cont));
}
template <typename Cont, typename Op>
fold_intermediate_2<Cont, Op, false> operator>(const Cont& cont, fold_intermediate_1<Op> f)
{
return fold_intermediate_2<Cont, Op, false>(cont, f.op);
}
template <typename Cont, typename Op, typename Init>
Init operator> (fold_intermediate_2<Cont, Op, false> f, Init init)
{
return foldr_func(f.op, init, std::begin(f.cont), std::end(f.cont));
}
foldr_func and foldl_func (the actual algorithms of left and right folds) are defined elsewhere.
Use it like this:
foo myfunc(foo, foo);
container<foo> cont;
foo zero, acc;
acc = cont >fold/myfunc> zero; // right fold
acc = cont <fold/myfunc< zero; // left fold
The word fold is used as a kind of poor man's new reserved word here. One can define several variations of this syntax, including
<<fold/myfunc<< >>fold/myfunc>>
<foldl/myfunc> <foldr/myfunc>
|fold<myfunc| |fold>myfunc|
The inner operator must have the same or greater precedence as the outer one(s). It's the limitation of C++ grammar.
For map, only one intermediate is needed and the syntax could be e.g.
mapped = cont |map| myfunc;
Implementing it is a simple exercise.
Oh, and please don't use this syntax in production, unless you know very well what you are doing, and probably even if you do ;)