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

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>>;

Related

Macro for nested maps in C++

Is it possible to create simple interface to create nested std::maps in C++? If this is possbile, can I go advanced and make it with different nested maps/vectors
CreateMaps(4); returns std::map<int,std::map<int,std::map<int,std::map<int,int>>>>>
CreateMaps(3); returns std::map<int,std::map<int,std::map<int,int>>>>
I am not really sure if this counts as macro or no.
My final target is to create maps at init and I want to divide into categories, type_0 has X subtypes which has Y subtypes and so on..., and I want to count how many times I reach certain scenario. Creating the map is defined after parsing a file, so I dont know the size and the number of nested maps at compile time.
Yes you can, even without macros, but by using recursive templates. Here is what it could look like:
// Recursive definition
template<typename T, size_t N>
struct NestedMap {
using type = std::map<T, typename NestedMap<T, N - 1>::type>;
};
// Termination condition for the recursion
template<typename T>
struct NestedMap<T, 0> {
using type = T;
};
// Just a convenience
template<typename T, size_t N>
using NestedMap_t = NestedMap<T, N>::type;
And then you can use it like so:
NestedMap_t<int, 4> quadmap;
quadmap[1][2][3][4] = 42;
However, nesting containers is often not very efficient, and you might get better performance by flattening your data structure. If you want to have a map that is indexed by four integers, then you could also do:
std::map<std::array<int, 4>, int> quadmap;
quadmap[{1, 2, 3, 4}] = 42;
The above types are fixed at compile time. If you want something more flexible, you should make the map's key and value more dynamic. Consider:
std::map<std::vector<int>, std::any> anymap;
anymap[{1, 2, 3, 4}] = 42;

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

Q: Generate argument list at compile time

I'm trying to create some tuple at compile time, just a type and a bitset (which represent the type for some operations).
I want something like:
<Foo1,0x001>, <Foo2,0x002>, <Foo3,0x003>...
That's why I have a Metadata struct:
template < typename T,
size_t Size >
struct Metadata {
using type = T;
std::bitset<Size> bitset;
};
And, thanks to everyone, the make function is something like that:
template <typename...Ts,typename...Args>
constexpr auto make_metadata(Args... args)
{
constexpr auto N = sizeof...(Ts);
return std::make_tuple(Metadata<Ts, N>{args}...);
}
But I need to give it the bitset value right now. And I know the bitset value at compile time as I said at the beginning. So how could I generate an argument list like (0,1,2,...,N - 1) ?
With C++14, you can use std::integer_sequence and std::make_integer_sequence() to generate a compile-time parameter pack of monotonically increasing integers, which should work in your use case.

Generate precomputed arrays using 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.

Check sizes are the same when compiling

I have a dictionary and an array neither of which change size during the program but could often be extended pre compilation. The number of keys and the array length should always be the same size. Is there a way to check this when compiling as it'd be easy to add the key but not to the array or visa versa?
There are ways to check compile time constants. In C++11 it has been cemented with static_assert but it's possible with templates as well.
For example given:
enum Key {
K_Zero,
K_One,
K_Two,
K_NUMBER_ELEMENTS
};
static char const Dictionary[] = { ... };
You would do it C++11:
static_assert(K_NUMBER_ELEMENTS == ARRAY_SIZE(Dictionary),
"Keys / Dictionary mismatch");
Where ARRAY_SIZE is defined as:
template <typename T, unsigned N>
char (&ComputeArraySize(T (&)[N]))[N];
#define ARRAY_SIZE(Array) sizeof(ComputeArraySize(Array))
If you are still in C++03 (which is probably the case if you don't know the version), then you ought to be a little more clever and replace the static_assert with:
template <unsigned M, unsigned N> struct mp_equal;
template <unsigned N> struct mp_equal<N,N> {};
namespace {
mp_equal<K_NUMBER_ELEMENTS, ARRAY_SIZE(Dictionary)>
AssertKeysAndDictionarySizeMatch = {};
}
Which will trigger a compile time error if they do not match.
Assuming by dictionary you mean map or unordered_map there's no immediate way to do it at compile time. You could runtime assert in main OR you could force the map to be always initialized from an array of pairs, and then static_assert that the length of the pair array is the same as your main array.