Generate precomputed arrays using templates? - c++

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.

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

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

How to construct a tuple from an array

I am designing a C++ library that reads a CSV file of reported data from some experiment and does some aggregation and outputs a pgfplots code. I want to make the library as generic and easy to use as possible. I also want to isolate it from the data types that are represented in the CSV file and leave the option to user to parse each column as she desires. I also want to avoid Boost Spirit Qi or other heavy duty parser.
The simple solution I have is for the user to create a type for each column, with a constructor that takes "char *". The constructor does its own parsing for the value it is given, which is one cell from the data. The user then passes me a list of types; the schema, representing the types in a line of data. I use this type list to create a tuple, in which every member of the tuple is responsible for parsing itself.
The problem now is how to initialise (construct) this tuple. Dealing with tuples is of course not straightforward since iterating over their elements is mostly a compile-time operation. I used Boost Fusion at first to achieve this task. However, the function I used (transform) although might take a tuple as input (with the appropriate adapter), it does not seem to return a tuple. I need the return value to be a tuple so some other code can use it as an associative type-to-value container (access it by type via std::get<T>), while using only standard tools, that is, without using Boost. So I had to convert whatever Fusion's transform returned into std::tuple.
My question is how to avoid this conversion, and better yet how to avoid Boost Fusion completely.
A simple solution that comes to mind is to use the constructor of std::tuple, and somehow pass each element its respective "const *" that it needs to construct. However, while this is possible using some complicated template-based enumeration techniques, I am wondering if there is a straightforward "parameter-pack"-like approach, or an even simpler way to pass the values to the constructors of the individual elements of a tuple.
To clarify what I am seeking, kindly take a look at this following code.
#include <cstdio>
#include <array>
template <typename...> struct format {};
template <typename...> struct file_loader {};
template <typename... Format>
struct
file_loader<format<Format...> > {
void load_file() {
size_t strsize = 500u;
char *str = new char[strsize]();
auto is = fopen("RESULT","r");
/* example of RESULT:
dataset2,0.1004,524288
dataset1,0.3253,4194304
*/
while(getline(&str, &strsize, is) >= 0) {
std::array<char*, 3> toks{};
auto s = str;
int i = 2;
while(i --> 0)
toks[i] = strsep (&s, ",");
toks[2] = strsep (&s, ",\n");
std::tuple<Format...> the_line{ /* toks */ } ; // <-- HERE
//// current solution:
// auto the_line{
// as_std_tuple( // <-- unnecessary conversion I'd like to avoid
// boost::fusion::transform(boost::fusion::zip(types, toks), boost::fusion::make_fused( CAST() ))
// )};
// do something with the_line
}
}
};
#include <string>
class double_type {
public:
double_type() {}
double_type(char const *token) { } // strtod
};
class int_type {
public:
int_type() {}
int_type(char const *token) { } // strtoul
};
int main(int argc, char *argv[]) {
file_loader< format< std::string,
double_type,
int_type > >
{}.load_file();
return 0;
}
I've highlighted the interesting line as "HERE" in a comment.
My question precisely is:
Is there a way to construct a std::tuple instance (of heterogeneous
types, each of which is implicitly convertible from "char *") with
automatic storage duration (on the stack) from a std::array<char *, N>,
where N equals the size of that tuple?
The answer I am seeking should
Avoid Boost Fusion
(Simplicity condition) Avoid using more than 5 lines of boilerplate template-based enumeration code
Alternatively, shows why this is not possible to do in the C++14 standard
The answer can use C++17 constructs, I wouldn't mind.
Thank you,
As with all questions involving std::tuple, use index_sequence to give you a parameter pack to index the array with:
template <class... Formats, size_t N, size_t... Is>
std::tuple<Formats...> as_tuple(std::array<char*, N> const& arr,
std::index_sequence<Is...>)
{
return std::make_tuple(Formats{arr[Is]}...);
}
template <class... Formats, size_t N,
class = std::enable_if_t<(N == sizeof...(Formats))>>
std::tuple<Formats...> as_tuple(std::array<char*, N> const& arr)
{
return as_tuple<Formats...>(arr, std::make_index_sequence<N>{});
}
Which you would use as:
std::tuple<Format...> the_line = as_tuple<Format...>(toks);

Populate An Array Using Constexpr at Compile-time

I would like to populate an array of enum using constexpr.
The content of the array follows a certain pattern.
I have an enum separating ASCII character set into four categories.
enum Type {
Alphabet,
Number,
Symbol,
Other,
};
constexpr Type table[128] = /* blah blah */;
I would like to have an array of 128 Type. They can be in a structure.
The index of the array will be corresponding to the ASCII characters and the value will be the Type of each character.
So I can query this array to find out which category an ASCII character belongs to. Something like
char c = RandomFunction();
if (table[c] == Alphabet)
DoSomething();
I would like to know if this is possible without some lengthy macro hacks.
Currently, I initialize the table by doing the following.
constexpr bool IsAlphabet (char c) {
return ((c >= 0x41 && c <= 0x5A) ||
(c >= 0x61 && c <= 0x7A));
}
constexpr bool IsNumber (char c) { /* blah blah */ }
constexpr bool IsSymbol (char c) { /* blah blah */ }
constexpr Type whichCategory (char c) { /* blah blah */ }
constexpr Type table[128] = { INITIALIZE };
where INITIALIZE is the entry point of some very lengthy macro hacks.
Something like
#define INITIALIZE INIT(0)
#define INIT(N) INIT_##N
#define INIT_0 whichCategory(0), INIT_1
#define INIT_1 whichCategory(1), INIT_2
//...
#define INIT_127 whichCategory(127)
I would like a way to populate this array or a structure containing the array without the need for this macro hack...
Maybe something like
struct Table {
Type _[128];
};
constexpr Table table = MagicFunction();
So, the question is how to write this MagicFunction?
Note: I am aware of cctype and likes, this question is more of a Is this possible? rather than Is this the best way to do it?.
Any help would be appreciated.
Thanks,
Ignoring ALL the issues, indices to the rescue:
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
template<unsigned... Is>
constexpr Table MagicFunction(seq<Is...>){
return {{ whichCategory(Is)... }};
}
constexpr Table MagicFunction(){
return MagicFunction(gen_seq<128>{});
}
Live example.
In C++17 ::std::array has been updated to be more constexpr friendly and you can do the same as in C++14, but without some of the scary looking hacks to get around the lack of constexpr in crucial places. Here is what the code would look like there:
#include <array>
enum Type {
Alphabet,
Number,
Symbol,
Other,
};
constexpr ::std::array<Type, 128> MagicFunction()
{
using result_t = ::std::array<Type, 128>;
result_t result = {Other};
result[65] = Alphabet;
//....
return result;
}
const ::std::array<Type, 128> table = MagicFunction();
Again MagicFunction still needs to obey the rather loose constexpr rules. Mainly, it may not modify any global variables or use new (which implies modifying global state, namely the heap) or other such things.
IMHO the best way to do this is simply write a tiny setup program that will generate table for you. And then you can either throw out the setup program, or check it in alongside the generated source code.
The tricky part of this question is just a duplicate of this other one: Is it possible to create and initialize an array of values using template metaprogramming?
The trick is, it's impossible to write anything like
Type table[256] = some_expression();
at file scope, because global arrays can be initialized only with literal (source-level) initializer-lists. You can't initialize a global array with the result of a constexpr function, even if you could somehow get that function to return a std::initializer_list, which you can't because its constructor isn't declared constexpr.
So what you have to do is get the compiler to generate the array for you, by making it a static const data member of a template class. After one or two levels of metaprogramming that I'm too confused to write out, you'll bottom out in a line that looks something like
template <int... Indices>
Type DummyStruct<Indices...>::table[] = { whichCategory(Indices)... };
where Indices is a parameter-pack that looks like 0,1,2,... 254,255. You construct that parameter-pack using a recursive helper template, or maybe just using something out of Boost. And then you can write
constexpr Type (&table)[] = IndexHelperTemplate<256>::table;
...But why would you do all that, when the table is only 256 entries that will never change unless ASCII itself changes? The right way is the simplest way: precompute all 256 entries and write out the table explicitly, with no templates, constexpr, or any other magic.
The way to do this in C++14 looks like this:
#include <array>
enum Type {
Alphabet,
Number,
Symbol,
Other,
};
constexpr ::std::array<Type, 128> MagicFunction()
{
using result_t = ::std::array<Type, 128>;
result_t result = {Other};
const result_t &fake_const_result = result;
const_cast<result_t::reference>(fake_const_result[65]) = Alphabet;
//....
return result;
}
const ::std::array<Type, 128> table = MagicFunction();
No clever template hackery required any longer. Though, because C++14 didn't really undergo a thorough enough review of what did and didn't have to be constexpr in the standard library, a horrible hack involving const_cast has to be used.
And, of course, MagicFunction had better not modify any global variables or otherwise violate the constexpr rules. But those rules are pretty liberal nowadays. You can, for example, modify all the local variables you want, though passing them by reference or taking their addresses may not work out so well.
See my other answer for C++17, which allows you to drop some of the ugly-looking hacks.

c++ functions with variable and not known number of arguments [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Variable number of arguments in C++?
May I not set the number of arguments of a function with variable number of arguments? As an example: can the following interface be implemented?
int sum(...) { ... }
sum(1, 2, 3, 4); // return 10
Conventional variadic functions are messy and not type-safe, but in C++11 you can do this cleanly using variadic templates and (compile-time) recursion:
// Base case for recursion
template <typename T>
inline T sum(T n) {
return n;
}
// Recursive case
template <typename T, typename... Args>
inline T sum(T n, Args... args) {
return n + sum(args...);
}
Since it's a template, this'll work for any types that have an operator+ defined:
std::cout << sum(1, 2, 3) << std::endl; // Prints 6
std::cout << sum(3.14, 2.72) << std::endl; // Prints 5.86
However, because the return type of the recursive template function is taken from the first argument only, you can get suprising results if you mix different argument types in one call: sum(2.5, 2) returns 4.5 as expected, but sum(2, 2.5) returns 2 because the return type is int, not double. If you want to be fancy, you can use the new alternative function syntax to specify that the return type is whatever the natural type of n + sum(args...) would be:
// Recursive case
template <typename T, typename... Args>
inline auto sum(T n, Args... args) -> decltype(n + sum(args...)) {
return n + sum(args...);
}
Now sum(2.5, 2) and sum(2, 2.5) both return 4.5.
If your actual logic is more complex than summation, and you don't want it inlined, you can use the inline template functions to put all the values into some sort of container (such as a std::vector or std::array) and pass that into the non-inline function to do the real work at the end.
You probably want to do this by writing the function to take something like a vector<int>, which you'll construct on the fly with a braced initializer list:
int sum(std::vector<int> const &n) {
return std::accumulate(begin(n), end(n), 0);
}
If there's some possibility the numbers might be (for example) floating point instead, you probably want to write it as a template instead:
template <class T>
T sum(std::vector<T> const &n) {
return std::accumulate(begin(n), end(n), T());
}
Either way, you'd invoke this just marginally differently:
int x = sum({1,2,3,4});
Warning: this feature was added to C++ fairly recently, so some compilers (e.g., VC++) don't support it yet -- though others (e.g., g++ 4.7+), do.
No, you can't.
Just don't use variable arguments. They suck in every conceivable fashion and are completely not worth anybody's time.
A C++ variadic function must know how many (and what type) of arguments it was passed. For example, printf's format string tells it what extra arguments to expect.
Your sum has no way of knowing if it got 4 ints or 10. You could make the 1st argument a length:
int sum(int howmany, ...) { ... }
so the function knows how many ints follow. But really you should just pass an array (or vector if you're feeling C++'y)
There are multiple ways to solve your issue. I'll go over a few:
Method 1:
-Create a series of overloaded sum functions to suit your needs.
Cons
-code bloat
This can be implemented by making multiple functions with headers:
int sum(int a);
int sum(int a, int b);
int sum(int a, int b, int c);
etc...
Method 2:
-create a custom class with a linked list, and pass in a pointer to the head of the linked list. This is probably your best move in this case, assuming you don't know the amount of data to be passed in.
Function header:
int sum(LinkedList *headPointer);
Method 3:
-pass in an array of variables
Function header:
int sum(int input[]);
Method 4:
-create a function with auto-set variables
Function header:
int sum(int a=0, int b=0, int c=0, int d=0,... int n=0);