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
Related
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>>;
I'm new to this so I may be missing things. I currently have these code:
#include <iostream>
template<int ...> struct mySum;
template<>struct
mySum<> {
static const int value = 0;
};
template<int i, int ... tail> struct
mySum<i, tail...> {
static const int value = i + mySum<tail...>::value;
};
int sum = mySum<1, 2, 3, 4, 5, 6, 7, 8>::value;
int main() {
std::cout << sum << std::endl;
return 0;
}
As you can see, I'm using recursion to get the sum of the values as an integer. How can I modify this code to accept a vector and return a vector?
For example, I want to multiply the entire vector by 2.
1,2,3,4 would return 2,4,6,8 etc...
Or are there better ways to recursively do this?
EDIT: The template stuff isn't a requirement. Only recursion. I just thought it might be possible to do this with templates...
If you want to do it recursively you have to use a function int sum(...); (including < stdarg.h >). (it's named a variadic function)
Templates is just a way to avoid rewriting things : all the template stuff is replaced during compilation : after compilation, templates don't exist anymore.
Because templates are determined at compilation time, only expressions known at compilation time (constant expressions) can be used in them.
Vectors by definition are not constant so they can't be used in templates.
Is there a good pattern that will let me use templates to generate a precomputed array from a given an element type, desired length, and custom function f(int index)?
Consider this C-style implementation.
#define FORLIST_1(fOfi) (fOfi)(0)
#define FORLIST_2(fOfi) FORLIST_1(fOfi) , (fOfi)(1 )
#define FORLIST_3(fOfi) FORLIST_2(fOfi) , (fOfi)(2 )
#define FORLIST_4(fOfi) FORLIST_3(fOfi) , (fOfi)(3 )
//... And so on
// Toy example user-specified function which describes how to create the table
double genEntry(u32 i) {
return i == 0 ? 0 : std::log(i) / std::log(5);
}
// Generate a precomputed lookup table
// FORLIST_15 expands into genEntry(0), genEntry(1), genEntry(2), ...
const double lookupTable[16] = {
FORLIST_16(genEntry)
};
What is the cleanest way to do the same thing with templates? It has to allow me to specify the number of elements in the array and allow me to supply some kind of user function (index as the parameter). Functors, std::function, lambda, function pointer, etc, are probably all acceptable ways to define the element generator.
I will probably want to explicit-instantiate the template once into an obj/lib so that the table itself is only defined once ever, as a linkable symbol instead of being recompiled into each .cpp file that includes the header.
With variadic template, you may do something like:
template <typename F, std::size_t ... Is>
auto
make_array(F f, std::index_sequence<Is...>)
-> std::array<std::decay_t<decltype(f(0u))>, sizeof...(Is)>
{
return {{f(Is)...}};
}
Live demo.
Note: decay_t, index_sequence and make_index_sequence are C++14 but can be written in C++11.
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.
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?