C++ template instantiation: Avoiding long switches - c++

I have a class depending on an integer template parameter. At one point in my program I want to use one instantiation of this template, depending on a value of this parameter determined at runtime. Here is a simple example demonstrating how I would go about this currently, using a big switch statement:
#include <string>
#include <iostream>
#include <type_traits>
template<unsigned A>
struct Wrapper {
typedef typename std::conditional<A==1, int, float>::type DataType;
DataType content[A];
void foo() {
std::cout << A << std::endl;
};
};
int main(int argc, char *argv[])
{
std::string arg = argv[1];
int arg_int = std::stoi(arg);
switch (arg_int) {
case 1: {
Wrapper<1> w;
w.foo();
break;
}
case 2: {
Wrapper<2> w;
w.foo();
break;
}
case 3: {
Wrapper<3> w;
w.foo();
break;
}
default:
return 1;
};
return 0;
}
This will quickly get unwieldy once I have not only one parameter A, but multiple template arguments in various combinations. Let's also assume that in reality there is a really good reason to implement A as a template parameter.
Is there a way to replace the huge switch statement with almost identical case statements, e.g. using some metaprogramming magic from Boost or a preprocessor hack?
Ideally I would like to be able write something like the following:
INSTANTIATE_DEPENDING(i, {1, 2, 3},
{
Wrapper<i> w;
w.foo();
}
);

You could use a variadic template, maybe like this:
#include <cstdlib>
#include <string>
int main(int argc, char * argv[])
{
if (argc != 2) { return EXIT_FAILURE; }
handle_cases<1, 3, 4, 9, 11>(std::stoi(argv[1]));
}
Implementation:
template <int ...> struct IntList {};
void handle_cases(int, IntList<>) { /* "default case" */ }
template <int I, int ...N> void handle_cases(int i, IntList<I, N...>)
{
if (I != i) { return handle_cases(i, IntList<N...>()); }
Wrapper<I> w;
w.foo();
}
template <int ...N> void handle_cases(int i)
{
handle_cases(i, IntList<N...>());
}

arg_int is a runtime parameter so there is no way to attach it directly to a template parameter. You could use some kind of handler table which would remove the switch statement here.
You'd use something like lookup_handler( int N ) returning a type handler which might be a lambda invoking one of those template functions.
Registering all your lambdas on the table could be done recursively starting with the highest numbered one you allow.
template< unsigned N > register_lambda()
{
table.add( Wrapper<N>() );
register_lambda< N-1 >;
}
and specialise for register_lambda<0>
Then somewhere you call register_lambda<32> say and you have registered all the numbers from 0 to 32.
One way to implement such a table is:
class lambda_table
{
typedef std::function<void()> lambda_type;
public:
void add( lambda_type );
bool lookup( size_t key, lambda_type & lambda ) const;
};
From main() or wherever you want to invoke it you have a reference to this table (call it table) then call
lambda_type lambda;
if( table.find( arg_int, lambda ) )
lanbda();
else
default_handler();
You might change this to give the table itself a default handler where none has been supplied for this number.
Although lambdas can wrap all kinds of data members you might actually want your templates to be classes in a hierarchy rather than lambdas given the data storage within them.

As an general alternative to switches, you could use a vector or map of function pointers to remove the switch:
template <int i>
int foo()
{
Wrapper<i> w;
w.foo();
return i;
}
static std::vector<int(*)()> m;
void init()
{
m.push_back(&foo<0>);
m.push_back(&foo<1>);
}
void bar(int i)
{
m[i]();
}
In C++11 you could use an initializer list to initialize the vector or map.

just use macros!
template<unsigned A>
struct Wrapper {
int content[A];
void foo() { };
};
#define WRAPPER_SWITCH_CASE(i) case i: Wrapper<i>().foo(); break;
int main(int argc, char *argv[])
{
std::string arg = argv[1];
int arg_int = std::stoi(arg);
switch (arg_int) {
WRAPPER_SWITCH_CASE(1)
WRAPPER_SWITCH_CASE(2)
WRAPPER_SWITCH_CASE(3)
default: return 1;
};
return 0;
}
(live example)
But as you know, macros are harmful; I think Wrapper should be allocate content at runtime, not template.

a short prof of concept application using a recursive generator for the Wrappers:
#include <iostream>
#include <vector>
struct FooProvider
{
virtual void foo() = 0;
};
template<unsigned A>
struct Wrapper : public FooProvider {
Wrapper() {std::cout << A << std::endl;}
int content[A];
virtual void foo() { std::cout << "call:" << A << std::endl;};
};
static std::vector<FooProvider*> providers;
template <unsigned CTR>
struct Instantiator
{
Instantiator()
{
providers.insert(providers.begin(), new Wrapper<CTR>);
Instantiator<CTR - 1>();
}
};
template <>
struct Instantiator<0>
{
Instantiator() {}
};
int main()
{
Instantiator<100>();
providers[4]->foo();
// do not forget to delete the providers
}

Here's another approach:
template<int N>
void do_foo()
{
Wrapper<N> w;
w.foo();
}
template<int N, int... Ns>
struct fn_table : fn_table<N - 1, N - 1, Ns...>
{
};
template<int... Ns>
struct fn_table<0, Ns...>
{
static constexpr void (*fns[])() = {do_foo<Ns>...};
};
template<int... Ns>
constexpr void (*fn_table<0, Ns...>::fns[sizeof...(Ns)])();
int main(int argc, char *argv[])
{
std::string arg = argv[1];
int arg_int = std::stoi(arg);
// 4 if you have Wrapper<0> to Wrapper<3>.
fn_table<4>::fns[arg_int]();
}

You could just use a higher-order looping macro that passes the block implementation to a generic loop expander:
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_ID(...) __VA_ARGS__
#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
//...etc
#define INSTANTIATE_DEPENDING(L, C) M_FOR_EACH(C, M_ID L)
//...
#define CASE_BLOCK(n) case n: { Wrapper<n> w; w.foo(); break; }
INSTANTIATE_DEPENDING((1, 2, 3), CASE_BLOCK)
#undef CASE_BLOCK //if you like, not essential to the concept
Not a lot to say about that: the loop repeats the block for the length of the passed list, passing the items in the list to the macro it is to expand. So you put your implementation in that macro (and #undef it if you want it to be local).
More elegantly (letting you nest the parameterized code to expand inside the expression where it belongs, instead of a second definition), you could use the rather high-end Order metaprogramming library:
#include <order/interpreter.h>
ORDER_PP( // runs Order code
8for_each_in_range(8fn(8I,
8print( (case) 8I (: { )
(Wrapper<) 8I (> w; w.foo(); break; }) )),
1, 4)
)
(Use 8for-each instead of 8for_each_in_range for non-contiguous lists. Order's got full functional programming semantics so such things are minor issues.)

Inspired by Kerrek SB's answer with variadic templates, here is a solution which can easily be extended to multiple parameters of any type:
template <int param1_>
struct Params
{
const static int kParam1 = param1_;
// Add other parameters here if needed
};
// Default case: list is empty
template <typename T>
void handle_cases(const T param1) { }
// Regular case: list is not-empty
template <typename T, typename head, typename ...tail>
void handle_cases(const T param1)
{
if (head::kParam1 == param1)
{
Wrapper<head::kParam1> w;
w.foo();
}
else
{
handle_cases<T, tail...>(param1);
}
}
Note that typename T is just an example of an additional template parameter which is not part of the head/tail list.
And here is how to use it:
int main(int argc, char * argv[])
{
if (argc != 2) { return EXIT_FAILURE; }
handle_cases<int, Params<1>, Params<3>, Params<4>, Params<9>, Params<11>>(std::stoi(argv[1]));
}

To explain #Simple's solution that is based on a static function table:
#include <iostream>
#include <vector>
using namespace std;
template<int N>
void do_foo()
{
cout << N << endl;
}
template<int N, int... Ns>
struct fn_table : fn_table<N - 1, N - 1, Ns...> {
};
template<int... Ns>
void p()
{
int a[] = {Ns...};
for (int i = 0; i < sizeof(a)/sizeof(int); ++i)
cout << a[i] << endl;
}
// Recursion-base instantiation with leading 0 parameter.
template<int... Ns>
struct fn_table<0, Ns...> {
// calling fn_table<4> would call recursively with template parameters: <4>, <3, 3>, <2, 2, 3>, <1, 1, 2, 3>, <0, 0, 1, 2, 3>. The last call would create 4 (we expand Ns without the first 0) do_foo functions using a variadic parameter pack "...".
static constexpr void (*fns[])() = {
p<Ns...> // call a function that prints Ns... for illustration, expanding the parameters inside p instead of duplicating it.
//do_foo<Ns>...
};
};
template<int... Ns>
constexpr void (*fn_table<0, Ns...>::fns[sizeof...(Ns)])();
int main(int argc, char *argv[])
{
int arg_int = 0;
// 4 if you have Wrapper<0> to Wrapper<3>.
fn_table<4>::fns[arg_int]();
}

Building the table using an integer_sequence. I also added: i) a sequence start, ii) a parameter for the type of the function, e.g. to receive and return values.
#include <iostream>
#include <vector>
using namespace std;
struct Foo {
template<int N>
static void foo(int &a) {
cout << N << endl;
a = N + 1;
}
};
template<int start, typename F, typename R, typename T, T... ints>
auto fn_table_( integer_sequence<T, ints...> int_seq )
{
vector<R> expand = { F::foo<ints+start>... };
vector<R> dummy( start );
expand.insert( expand.begin(), dummy.begin(), dummy.end() );
return expand;
}
template<int start, typename F, typename R, int N>
auto fn_table()
{
return fn_table_<start, F, R>( make_integer_sequence<int, N-start>{} );
}
void main()
{
int arg_int = 5;
typedef void (*fun_type)( int & );
auto fns = fn_table<4, Foo, fun_type, 7>();
int a;
fns[arg_int]( a );
cout << a << endl;
cout << "all:\n";
for (int i = 0; i < fns.size() ; ++i)
if ( fns[i] )
fns[i]( a );
}

Related

Is it possible to create an initializer_list from an enum?

Is it possible to declare a static initializer_list with elements in an enum, without explicitly declaring it, in order to use it as default argument? Example:
#include <initializer_list>
#include <iostream>
enum ID {
A,
B,
C,
D
};
inline constexpr std::initializer_list< ID > all { A, B, C, D };
void func(const std::initializer_list< ID >& args = all) {
for (const auto& arg : args) {
std::cout << arg << std::endl;
}
}
int main(int argc, char const *argv[]) {
/* code */
func(); // prints 'all' contents
return 0;
}
However, I would like to avoid having to explicit declare an ID list in two places. I understand I could use a std::vector for that purpose:
#include <initializer_list>
#include <iostream>
#include <vector>
enum ID {
A,
B,
C,
D,
// ...
MAX = D
};
inline std::vector< ID > all() {
std::vector< ID > list(ID::MAX + 1);
for (int i = ID::A; i <= ID::MAX; i++) {
list[i] = static_cast< ID >(i);
}
return list;
}
void func(const std::vector< ID >& args = all()) {
for (const auto& arg : args) {
std::cout << arg << std::endl;
}
}
int main(int argc, char const *argv[]) {
/* code */
func();
return 0;
}
but I am curious if it is possible to implement this with std::initializer_list.
enum IDs {
A,
B,
C,
D,
ENUM_COUNT,
};
template<class E>
using enum_indexes_t = std::make_index_sequence<static_cast<std::size_t>( E::ENUM_COUNT )>;
template<class E>
constexpr enum_indexes_t<E> enum_indexes_v = {};
template<class E, std::size_t...Is>
constexpr auto enum_list( std::index_sequence<Is...> ) {
return std::integer_sequence<E, static_cast<E>(Is)... >{};
}
template<class E>
constexpr auto enum_list() {
return enum_list<E>( enum_indexes_v<E> );
}
template<class Es>
struct to_initializer_list;
template<class E, E... es>
struct to_initializer_list< std::integer_sequence<E,es...> > {
static inline constexpr std::initializer_list<E> list = {es...};
};
template<class E>
constexpr auto enum_il_v = to_initializer_list< decltype( enum_list<E>() ) >::list;
then enum_il_v<IDs> is an initializer list referencing a global-scope array containing A through D.
The keys here are (a) ENUM_COUNT a "famous" end of enum we add to the enum, and (b) the elements of the enum are contiguous from 0 up to ENUM_COUNT but not including.
You can work around ENUM_COUNT by adding a different way to get the count. There is no practical way to work around the need for the elements to be contiguous, unless they match some other simple known pattern, using this technique.
Other alternatives include waiting for reflection to arrive in C++, or use of macros or other preprocessing techniques (like code generation).

Can you call a compile-time instantiated template function with a run-time specified variable?

I have a function with an integer template parameter:
template<int N>
int func() {
return N;
}
I explicitly instantiate the template for all template arguments I might provide:
template int func<1>();
template int func<2>();
template int func<3>();
//...
I then want to call func with a run-time specified integer n:
//This code does not compile
int main() {
int n;
std::cin >> n;
// check that n is one of the allowed values
std::cout << func<n>(); // can fail if given a bad n
return 0;
}
Are there modifications I can make to this code to call func<n>() with n specified at run-time (say 0 < n < 20)?
Yes, it's possible, but not quite the way you're trying, because the template syntax like F<N> requires compile time values. However, once instantiated, they are regular functions and you can take function pointers to them, or put them in std::function, etc.
You can, for example, build an array for function pointers that allow access by a runtime index, something as follows:
template <int N>
int f() { return N; } // your function(s)
int main()
{
using Func = int(*)();
Func funcs[]{f<0>, f<1>, f<2>, }; // array of instances of f
// call a function via runtime value stored in n:
int n = 2;
funcs[n]();
}
Give the runtime program a list of functions to choose from and have it pick using an index (live example):
template<std::size_t... Indices>
int call_func_impl(std::index_sequence<Indices...>, int n) {
using FuncType = int(*)();
static const FuncType funcs[] = {func<Indices>...};
return funcs[n]();
}
template<int MaxN>
int call_func(int n) {
return call_func_impl(std::make_index_sequence<MaxN>{}, n);
}
...
call_func<20>(n);
Naturally, you could create the array manually (func<0>, func<1>, ...), but this wraps it up a bit more nicely. If you need a sequence other than 0 through N-1, use std::integer_sequence. If you need a non-sequence, there's no ready-made helper, though you can adapt one of the above if there's a pattern to arrive at the values you want (e.g., multiply each index_sequence element by 2 to get even numbers).
For completeness, C++20 enables a lovely (at least if you're used to worse) pattern for reducing copy-paste arguments:
template<int MaxN>
int call_func(int n) {
const auto impl = [n]<std::size_t... Indices>(std::index_sequence<Indices...>) {
using FuncType = int(*)();
static const FuncType funcs[] = {func<Indices>...};
return funcs[n]();
};
return impl(std::make_index_sequence<MaxN>{});
}
Here is a solution with simple caller function allowing to call your func when using integers from 1 to 20
#include <cassert>
#include <iostream>
template<int N>
int func() { return N; }
template <int N>
int callFunc(int n)
{
if (n==N) return func<N>();
else return callFunc<N-1>(n);
}
template <>
int callFunc<0>(int n)
{
assert(false);
return 0;
}
#define MAX_N 20
int main() {
int n;
std::cin >> n;
std::cout << callFunc<MAX_N>(n);
return 0;
}
If you can use C++17, another way using folding
#include <utility>
#include <iostream>
template <int N>
int func()
{ return N; }
template <int ... Is>
int func2 (int n, std::integer_sequence<int, Is...>)
{
int ret {};
if ( false == ( ... || (Is == n ? (ret = func<Is>(), true) : false) ) )
throw std::runtime_error{"no matching func()"};
return ret;
}
template <int I = 20>
int func3 (int n)
{ return func2(n, std::make_integer_sequence<int, I>{}); }
int main()
{
int n;
std::cin >> n;
std::cout << func3(n) << std::endl;
}
Starting from C++20, you can also use template lambdas, so you can also write
#include <utility>
#include <iostream>
template <int N>
int func()
{ return N; }
int main()
{
int n;
std::cin >> n;
std::cout << []<int ... Is>(int n, std::integer_sequence<int, Is...>)
{
int ret {};
if ( false == ( ... || (Is == n ? (ret = func<Is>(), true) : false) ) )
throw std::runtime_error{"no matching func()"};
return ret;
}(n, std::make_integer_sequence<int, 20>{}) << std::endl;
}

C++ templates to avoid long switches, while calling a function with different return types

I have many functions q1, q2, q3, etc., each with a different return type (int, int64_t, std::string, etc.).
I also have a print_result function that prints out their results (and the time they take to run, but trimmed here for simplicity):
template <typename T>
void print_result(T (*func)()) {
T res = func();
std::cout << res << std::endl;
}
I also have big switch statement to print the result for each of the functions:
switch (question_num) {
case 1: print_result(q1); break;
case 2: print_result(q2); break;
case 3: print_result(q3); break;
// ...
}
Objective: I would like to replace this switch statement with a template function, to avoid copying each line every time I add a new function.
I have tried to look at C++ template instantiation: Avoiding long switches, but I'm new to template metaprogramming, so not sure how to handle this exactly.
My current attempt that doesn't compile:
template <<int, typename> ...> struct FuncList {};
template <typename T>
bool handle_cases(int, T, FuncList<>) {
// default case
return false;
}
template <<int I, typename T> ...S>
bool handle_cases(int i, T (*func)(), FuncList<T, S...>) {
if (I != i) {
return handle_cases(i, func, FuncList<S...>());
}
print_result(func);
return true;
}
template <typename ...S>
bool handle_cases(int i, T (*func)()) {
return handle_cases(i, func, FuncList<S...>());
}
// ...
bool res = handle_cases<
<1, q1>, <2, q2>, <3, q3>
>(question_num);
// ...
My ideal way of using this template is shown at the last line there.
Note that the mappings from the function number to the function is provided there. The function numbers are fixed, i.e. q1 maps to the constant 1 and that won't change at runtime.
The compilation error (it might be rather basic but I really don't know much about metaprogramming):
error: expected unqualified-id before ‘<<’ token
17 | template <<int, typename> ...> struct FuncList {};
| ^~
If you can use c++17, here's a "simplified" version of #Klaus's approach. Instead of using a had-made recursive structure, you could use a c++17 fold-expression:
template<auto... Funcs, std::size_t... I>
bool select_case(std::size_t i, std::integer_sequence<std::size_t, I...>) {
return ([&]{ if(i == I) { print_result(Funcs); return true; } return false; }() || ... );
}
template<auto... Funcs>
struct FuncSwitch {
static bool Call(std::size_t i) {
return select_case<Funcs...>(i, std::make_index_sequence<sizeof...(Funcs)>());
}
};
The idea is to wrap each of Funcs in a lambda such that only the function corresponding to the index passed is called. Note that the || in the fold expression short-circuits.
Would be used like this:
float q0() { return 0.f; }
int q1() { return 1; }
std::string q2() { return "two"; }
int main() {
bool success = FuncSwitch<q0, q1, q2>::Call(1);
}
See here for a complete example.
I've got a different proposal:
Use an std::array instead of switch (or std::map if the switch cases are non-continuous, std::array has O(1) access time, std::map O(log(n)) and switch O(n).
Use std::function and std::bind to bind your functions you want to call to a functor object
use the index into the array to call the function
Use placeholders if you need to pass additional data
#include <iostream>
#include <functional>
template <typename T>
void print_result(T (*func)()) {
T res = func();
std::cout << res << std::endl;
}
int int_function() {
return 3;
}
double double_function() {
return 3.5;
}
std::array<std::function<void()>, 2> functions({
std::bind(print_result<int>, int_function),
std::bind(print_result<double>, double_function),
});
int main() {
functions[0]();
functions[1]();
return 0;
}
Output:
3
3.5
See: Why does std::function can implicit convert to a std::function which has more parameter?
Update:
With parameter passing:
#include <iostream>
#include <functional>
template <typename T>
void print_result(T (*func)(int), int value) {
T res = func(value);
std::cout << res << std::endl;
}
int int_function(int value) {
return 3 * value;
}
double double_function(int value) {
return 3.5 * value;
}
std::array<std::function<void(int)>, 2> functions({
std::bind(print_result<int>, int_function, std::placeholders::_1),
std::bind(print_result<double>, double_function, std::placeholders::_1),
});
int main() {
functions[0](10);
functions[1](11);
return 0;
}
Output:
30
38.5
You may like a version which do not need any kind of runtime containers, did not generate any objects in between and even do not generate a data table and generates very less code and is also easy to use:
// Example functions
int fint() { return 1; }
double fdouble() { return 2.2; }
std::string fstring() { return "Hallo"; }
// your templated result printer
template < typename T>
void print_result( T parm )
{
std::cout << "The result of call is " << parm << std::endl;
}
// lets create a type which is able to hold functions
template < auto ... FUNCS >
struct FUNC_CONTAINER
{
static constexpr unsigned int size = sizeof...(FUNCS);
};
// and generate a interface to switch
template < unsigned int, typename T >
struct Switch_Impl;
template < unsigned int IDX, auto HEAD, auto ... TAIL >
struct Switch_Impl< IDX, FUNC_CONTAINER<HEAD, TAIL...>>
{
static void Do( unsigned int idx )
{
if ( idx == IDX )
{
// Your function goes here
print_result(HEAD());
}
else
{
if constexpr ( sizeof...(TAIL))
{
Switch_Impl< IDX+1, FUNC_CONTAINER<TAIL...>>::Do(idx);
}
}
}
};
// a simple forwarder to simplify the interface
template < typename T>
struct Switch
{
static void Do(unsigned int idx )
{
Switch_Impl< 0, T >::Do( idx );
}
};
// and lets execute the stuff
int main()
{
using FUNCS = FUNC_CONTAINER< fint, fdouble, fstring >;
for ( unsigned int idx = 0; idx< FUNCS::size; idx++ )
{
Switch<FUNCS>::Do(idx);
}
}
Given you "current attempt"... it seems to me that you could write a handle_cases struct/class almost as follows
struct handle_cases
{
std::map<int, std::function<void()>> m;
template <typename ... F>
handle_cases (std::pair<int, F> const & ... p)
: m{ {p.first, [=]{ print_result(p.second); } } ... }
{ }
void operator() (int i)
{ m[i](); }
};
with a map between an integer and a lambda that call print_result with the function and an operator() that call the requested lambda, given the corresponding index.
You can create an object of the class as follows (unfortunately I don't see a way to avoid the std::make_pair()s)
handle_cases hc{ std::make_pair(10, q1),
std::make_pair(20, q2),
std::make_pair(30, q3),
std::make_pair(40, q4) };
and using it as follows
hc(30);
The following is a full compiling example
#include <functional>
#include <map>
#include <iostream>
template <typename T>
void print_result (T(*func)())
{
T res = func();
std::cout << res << std::endl;
}
struct handle_cases
{
std::map<int, std::function<void()>> m;
template <typename ... F>
handle_cases (std::pair<int, F> const & ... p)
: m{ {p.first, [=]{ print_result(p.second); } } ... }
{ }
void operator() (int i)
{ m[i](); }
};
char q1 () { return '1'; }
int q2 () { return 2; }
long q3 () { return 3l; }
long long q4 () { return 4ll; }
int main ()
{
handle_cases hc{ std::make_pair(10, q1),
std::make_pair(20, q2),
std::make_pair(30, q3),
std::make_pair(40, q4) };
hc(30);
}

Recreate function signature and call via template packs in C++

I have C code that I want to rewrite in C++. The C code is part of a interpreter where the functions are defined in C however the actual call is from the interpreted source. Basically what it does is listed below:
#include <vector>
void f1(int a0) { }
void f2(int a0,int a1) { }
void f3(int a0,int a1,int a2) { }
void f4(int a0,int a1,int a2,int a3) { }
struct m {
void *p;
int c;
};
std::vector<m> ma;
int addfunc(void *p, int c) {
int i = ma.size();
ma.push_back({p,c});
return i;
}
void call(int idx, int *stack) {
switch (ma[idx].c) {
case 1:
((void (*)(int))ma[idx].p) (stack[0]);
break;
case 2:
((void (*)(int,int))ma[idx].p) (stack[0],stack[1]);
break;
case 3:
((void (*)(int,int,int))ma[idx].p) (stack[0],stack[1],stack[2]);
break;
case 4:
((void (*)(int,int,int,int))ma[idx].p) (stack[0],stack[1],stack[2],stack[3]);
break;
}
}
int main (void) {
int stack[5] = { 0,1,2,3,4 };
/* define */
int i1 = addfunc((void*)f1, 1);
int i2 = addfunc((void*)f2, 2);
int i3 = addfunc((void*)f3, 3);
int i4 = addfunc((void*)f4, 4);
/* call */
call(i1,stack);
call(i2,stack);
call(i3,stack);
call(i4,stack);
}
The addfunc creates a callable object specified by a function pointer and a signature, because the arguments are of the same type int only a count argument for the number of arguments is needed.
When I call a function I specify the function object's index and a stack. The actual c-call is decoded via the argument count and typecasted, the call arguments are taken from the stack.
How can I rewrite the addfunc and call functions as templates objects in C++? How can I use template packs to count the number of arguments for the given function and regenerate the call to the function?
How can I get rid of the switch statement and the function pointer typecast? I have seen that luawrapper's Binder class does something similar. However the code is quite complicated. In my case the arguments are all of the same type.
In the end I want to do something like (pseudocode):
vector<meth> ma;
...
int i0 = addfunc([](int a) { });
int i1 = addfunc([](int a,int b) { });
int i2 = addfunc([](int a,int b,int b) { });
int i3 = addfunc([](int a,int b,int c,int c) { });
...
ma[i0](stack);
ma[i1](stack);
ma[i2](stack);
ma[i3](stack);
Well, if they're just C functions, why not overload on the function pointer type?
std::function<void(std::array<int, 5>)> addfunc(void (*f)(int)) {
return [f](std::array<int, 5> const& a) { f(a[0]); };
}
std::function<void(std::array<int, 5>)> addfunc(void (*f)(int,int)) {
return [f](std::array<int, 5> const& a) { f(a[0], a[1]); };
}
// repeat for all necessary arities
Then create std::vector<std::function<void(std::array<int, 5>)>> and push back all your functions. It's easy, doesn't require any templates and will work reasonably well. It introduces the overhead of std::function, though.
You could get rid of that by introducing your own callable type (n of them), that would correspond to the overloads above, provide an operator() and store appropriate function type inside.
Live example.
Unfortunately, you won't be able to make a completely generic solution, as there is no way to type-erase arity.
One way you can simplify things would be to create a set of wrappers for your functions, each wrapper accepting a stack*, and calling implementation functions with arguments from said stack.
Than you do not need typecasts at all and a simple function pointer (to approriate wrapper) would do (no even need to type-erase).
I propose a C++17 solution (simplified following a Jarod42's observation: thanks) that I suppose is over-complicated.
But I find it funny...
First: a struct that, given (as template parameters) a type and a unsigned number, define a type as the type received.
template <typename T, std::size_t>
struct getType
{ using type = T; };
It's used to convert a variadic template list of numbers in a sequence of types (ints, in the following example) of the same length.
Next: a template type that register (setFunc()) and exec (callFunc()) a function returning void and a sequence of ints length as the first template parameter.
template <std::size_t N, typename = std::make_index_sequence<N>>
struct frHelper;
template <std::size_t N, std::size_t ... Is>
struct frHelper<N, std::index_sequence<Is...>>
{
using fnPnt_t = void(*)(typename getType<int, Is>::type...);
fnPnt_t fp = nullptr;
void setFunc (fnPnt_t fp0)
{ fp = fp0; }
void callFunc (std::array<int, sizeof...(Is)> const & a)
{ if ( fp ) fp(a[Is]...); }
};
Last: a template struct that inherit from a variadic list of preceding structs and enable (using) the setFunc() and the callFunc() members.
template <std::size_t N, typename = std::make_index_sequence<N>>
struct funcRegister;
template <std::size_t N, std::size_t ... Is>
struct funcRegister<N, std::index_sequence<Is...>>
: public frHelper<Is>...
{
using frHelper<Is>::setFunc...;
using frHelper<Is>::callFunc...;
};
Use.
First you have to declare an object of type funcRegister<N> where N is the max number of integer received from your functions plus one. So if you want to use f4(), so four integers, you have to declare
funcRegister<5u> fr;
Then you have to register the functions
fr.setFunc(f1);
fr.setFunc(f2);
fr.setFunc(f3);
fr.setFunc(f4);
and, given some std::array<int, N> of the right size, you can call the registered functions
std::array a1 { 1 };
std::array a2 { 1, 2 };
std::array a3 { 1, 2, 3 };
std::array a4 { 1, 2, 3, 4 };
fr.callFunc(a1); // call f1
fr.callFunc(a2); // call f2
fr.callFunc(a3); // call f3
fr.callFunc(a4); // call f4
The following is a full compiling C++17 example
#include <array>
#include <utility>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t>
struct getType
{ using type = T; };
template <std::size_t N, typename = std::make_index_sequence<N>>
struct frHelper;
template <std::size_t N, std::size_t ... Is>
struct frHelper<N, std::index_sequence<Is...>>
{
using fnPnt_t = void(*)(typename getType<int, Is>::type...);
fnPnt_t fp = nullptr;
void setFunc (fnPnt_t fp0)
{ fp = fp0; }
void callFunc (std::array<int, sizeof...(Is)> const & a)
{ if ( fp ) fp(a[Is]...); }
};
template <std::size_t N, typename = std::make_index_sequence<N>>
struct funcRegister;
template <std::size_t N, std::size_t ... Is>
struct funcRegister<N, std::index_sequence<Is...>>
: public frHelper<Is>...
{
using frHelper<Is>::setFunc...;
using frHelper<Is>::callFunc...;
};
void f1(int) { std::cout << "f1 called" << std::endl; }
void f2(int,int) { std::cout << "f2 called" << std::endl;}
void f3(int,int,int) { std::cout << "f3 called" << std::endl;}
void f4(int,int,int,int) { std::cout << "f4 called" << std::endl;}
int main()
{
funcRegister<5u> fr;
fr.setFunc(f1);
fr.setFunc(f2);
fr.setFunc(f3);
fr.setFunc(f4);
std::array a1 { 1 };
std::array a2 { 1, 2 };
std::array a3 { 1, 2, 3 };
std::array a4 { 1, 2, 3, 4 };
fr.callFunc(a1);
fr.callFunc(a2);
fr.callFunc(a3);
fr.callFunc(a4);
}
Here is luawrapper's code extracted to be applied the above case. This is more for completion as for #Jerod42's code is preferable.
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <functional>
#include <vector>
template<typename T> struct tag {};
template<typename TFunctionObject, typename TFirstParamType>
struct Binder {
TFunctionObject function;
TFirstParamType param;
template<typename... TParams>
auto operator()(TParams&&... params)
-> decltype(function(param, std::forward<TParams>(params)...))
{
return function(param, std::forward<TParams>(params)...);
}
};
template<typename TCallback>
static void readIntoFunction(int *stack, TCallback&& callback)
{
callback();
}
template<typename TCallback, typename TFirstType, typename... TTypes>
static void readIntoFunction(int *stack, TCallback&& callback, tag<TFirstType>, tag<TTypes>... othersTags)
{
Binder<TCallback, const TFirstType&> binder{ callback, *stack };
return readIntoFunction(++stack, binder, othersTags...);
}
/* decompose arguments */
template<typename TFunctionType, typename... TOtherParams>
std::function<void(int*)> _addfunc(TFunctionType f, tag<void (*)(TOtherParams...)>) {
return std::function<void(int*)>([f](int *stack) {
readIntoFunction(stack, f, tag<TOtherParams>{}...);
});
}
template<typename TFunctionType>
std::function<void(int*)> addfunc(TFunctionType fn)
{
typedef typename std::decay<TFunctionType>::type RealFuncSig;
return _addfunc(std::move(fn), tag<RealFuncSig>{} );
}
void f1(int a0) { std::cout << a0 << std::endl; }
void f2(int a0, int a1) { std::cout << a0 << a1 << std::endl; }
int main() {
int stack[5] = { 0,1,2,3,4 };
auto a0 = addfunc(&f1);
auto a1 = addfunc(&f2);
a0(stack);
a1(stack);
}
you can use std:function as the parameter of the addfun() and also std::bind

C++11: Compile Time Calculation of Array

Suppose I have some constexpr function f:
constexpr int f(int x) { ... }
And I have some const int N known at compile time:
Either
#define N ...;
or
const int N = ...;
as needed by your answer.
I want to have an int array X:
int X[N] = { f(0), f(1), f(2), ..., f(N-1) }
such that the function is evaluated at compile time, and the entries in X are calculated by the compiler and the results are placed in the static area of my application image exactly as if I had used integer literals in my X initializer list.
Is there some way I can write this? (For example with templates or macros and so on)
Best I have: (Thanks to Flexo)
#include <iostream>
#include <array>
using namespace std;
constexpr int N = 10;
constexpr int f(int x) { return x*2; }
typedef array<int, N> A;
template<int... i> constexpr A fs() { return A{{ f(i)... }}; }
template<int...> struct S;
template<int... i> struct S<0,i...>
{ static constexpr A gs() { return fs<0,i...>(); } };
template<int i, int... j> struct S<i,j...>
{ static constexpr A gs() { return S<i-1,i,j...>::gs(); } };
constexpr auto X = S<N-1>::gs();
int main()
{
cout << X[3] << endl;
}
There is a pure C++11 (no boost, no macros too) solution to this problem. Using the same trick as this answer we can build a sequence of numbers and unpack them to call f to construct a std::array:
#include <array>
#include <algorithm>
#include <iterator>
#include <iostream>
template<int ...>
struct seq { };
template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };
template<int ...S>
struct gens<0, S...> {
typedef seq<S...> type;
};
constexpr int f(int n) {
return n;
}
template <int N>
class array_thinger {
typedef typename gens<N>::type list;
template <int ...S>
static constexpr std::array<int,N> make_arr(seq<S...>) {
return std::array<int,N>{{f(S)...}};
}
public:
static constexpr std::array<int,N> arr = make_arr(list());
};
template <int N>
constexpr std::array<int,N> array_thinger<N>::arr;
int main() {
std::copy(begin(array_thinger<10>::arr), end(array_thinger<10>::arr),
std::ostream_iterator<int>(std::cout, "\n"));
}
(Tested with g++ 4.7)
You could skip std::array entirely with a bit more work, but I think in this instance it's cleaner and simpler to just use std::array.
You can also do this recursively:
#include <array>
#include <functional>
#include <algorithm>
#include <iterator>
#include <iostream>
constexpr int f(int n) {
return n;
}
template <int N, int ...Vals>
constexpr
typename std::enable_if<N==sizeof...(Vals),std::array<int, N>>::type
make() {
return std::array<int,N>{{Vals...}};
}
template <int N, int ...Vals>
constexpr
typename std::enable_if<N!=sizeof...(Vals), std::array<int,N>>::type
make() {
return make<N, Vals..., f(sizeof...(Vals))>();
}
int main() {
const auto arr = make<10>();
std::copy(begin(arr), end(arr), std::ostream_iterator<int>(std::cout, "\n"));
}
Which is arguably simpler.
Boost.Preprocessor can help you. The restriction, however, is that you have to use integral literal such as 10 instead of N (even be it compile-time constant):
#include <iostream>
#include <boost/preprocessor/repetition/enum.hpp>
#define VALUE(z, n, text) f(n)
//ideone doesn't support Boost for C++11, so it is C++03 example,
//so can't use constexpr in the function below
int f(int x) { return x * 10; }
int main() {
int const a[] = { BOOST_PP_ENUM(10, VALUE, ~) }; //N = 10
std::size_t const n = sizeof(a)/sizeof(int);
std::cout << "count = " << n << "\n";
for(std::size_t i = 0 ; i != n ; ++i )
std::cout << a[i] << "\n";
return 0;
}
Output (ideone):
count = 10
0
10
20
30
40
50
60
70
80
90
The macro in the following line:
int const a[] = { BOOST_PP_ENUM(10, VALUE, ~) };
expands to this:
int const a[] = {f(0), f(1), ... f(9)};
A more detail explanation is here:
BOOST_PP_ENUM
If you want the array to live in static memory, you could try this:
template<class T> struct id { typedef T type; };
template<int...> struct int_pack {};
template<int N, int...Tail> struct make_int_range
: make_int_range<N-1,N-1,Tail...> {};
template<int...Tail> struct make_int_range<0,Tail...>
: id<int_pack<Tail...>> {};
#include <array>
constexpr int f(int n) { return n*(n+1)/2; }
template<class Indices = typename make_int_range<10>::type>
struct my_lookup_table;
template<int...Indices>
struct my_lookup_table<int_pack<Indices...>>
{
static const int size = sizeof...(Indices);
typedef std::array<int,size> array_type;
static const array_type& get()
{
static const array_type arr = {{f(Indices)...}};
return arr;
}
};
#include <iostream>
int main()
{
auto& lut = my_lookup_table<>::get();
for (int i : lut)
std::cout << i << std::endl;
}
If you want a local copy of the array to work on, simply remove the ampersand.
There are quite a few great answers here. The question and tags specify c++11, but as a few years have passed, some (like myself) stumbling upon this question may be open to using c++14. If so, it is possible to do this very cleanly and concisely using std::integer_sequence; moreover, it can be used to instantiate much longer arrays, since the current "Best I Have" is limited by recursion depth.
constexpr std::size_t f(std::size_t x) { return x*x; } // A constexpr function
constexpr std::size_t N = 5; // Length of array
using TSequence = std::make_index_sequence<N>;
static_assert(std::is_same<TSequence, std::integer_sequence<std::size_t, 0, 1, 2, 3, 4>>::value,
"Make index sequence uses std::size_t and produces a parameter pack from [0,N)");
using TArray = std::array<std::size_t,N>;
// When you call this function with a specific std::integer_sequence,
// the parameter pack i... is used to deduce the the template parameter
// pack. Once this is known, this parameter pack is expanded in
// the body of the function, calling f(i) for each i in [0,N).
template<std::size_t...i>
constexpr TArray
get_array(std::integer_sequence<std::size_t,i...>)
{
return TArray{{ f(i)... }};
}
int main()
{
constexpr auto s = TSequence();
constexpr auto a = get_array(s);
for (const auto &i : a) std::cout << i << " "; // 0 1 4 9 16
return EXIT_SUCCESS;
}
I slightly extended the answer from Flexo and Andrew Tomazos so that the user can specify the computational range and the function to be evaluated.
#include <array>
#include <iostream>
#include <iomanip>
template<typename ComputePolicy, int min, int max, int ... expandedIndices>
struct ComputeEngine
{
static const int lengthOfArray = max - min + sizeof... (expandedIndices) + 1;
typedef std::array<typename ComputePolicy::ValueType, lengthOfArray> FactorArray;
static constexpr FactorArray compute( )
{
return ComputeEngine<ComputePolicy, min, max - 1, max, expandedIndices...>::compute( );
}
};
template<typename ComputePolicy, int min, int ... expandedIndices>
struct ComputeEngine<ComputePolicy, min, min, expandedIndices...>
{
static const int lengthOfArray = sizeof... (expandedIndices) + 1;
typedef std::array<typename ComputePolicy::ValueType, lengthOfArray> FactorArray;
static constexpr FactorArray compute( )
{
return FactorArray { { ComputePolicy::compute( min ), ComputePolicy::compute( expandedIndices )... } };
}
};
/// compute 1/j
struct ComputePolicy1
{
typedef double ValueType;
static constexpr ValueType compute( int i )
{
return i > 0 ? 1.0 / i : 0.0;
}
};
/// compute j^2
struct ComputePolicy2
{
typedef int ValueType;
static constexpr ValueType compute( int i )
{
return i * i;
}
};
constexpr auto factors1 = ComputeEngine<ComputePolicy1, 4, 7>::compute( );
constexpr auto factors2 = ComputeEngine<ComputePolicy2, 3, 9>::compute( );
int main( void )
{
using namespace std;
cout << "Values of factors1" << endl;
for ( int i = 0; i < factors1.size( ); ++i )
{
cout << setw( 4 ) << i << setw( 15 ) << factors1[i] << endl;
}
cout << "------------------------------------------" << endl;
cout << "Values of factors2" << endl;
for ( int i = 0; i < factors2.size( ); ++i )
{
cout << setw( 4 ) << i << setw( 15 ) << factors2[i] << endl;
}
return 0;
}
Here's a more concise answer where you explicitly declare the elements in the original sequence.
#include <array>
constexpr int f(int i) { return 2 * i; }
template <int... Ts>
struct sequence
{
using result = sequence<f(Ts)...>;
static std::array<int, sizeof...(Ts)> apply() { return {{Ts...}}; }
};
using v1 = sequence<1, 2, 3, 4>;
using v2 = typename v1::result;
int main()
{
auto x = v2::apply();
return 0;
}
How about this one?
#include <array>
#include <iostream>
constexpr int f(int i) { return 2 * i; }
template <int N, int... Ts>
struct t { using type = typename t<N - 1, Ts..., 101 - N>::type; };
template <int... Ts>
struct t<0u, Ts...>
{
using type = t<0u, Ts...>;
static std::array<int, sizeof...(Ts)> apply() { return {{f(Ts)...}}; }
};
int main()
{
using v = typename t<100>::type;
auto x = v::apply();
}
I don't think that's the best way to do this, but one can try somewhat like this:
#include <array>
#include <iostream>
#include <numbers>
constexpr auto pi{std::numbers::pi_v<long double>};
template <typename T>
struct fun
{
T v;
explicit constexpr fun(T a) : v{a * a} {}
};
template <size_t N, typename T, typename F>
struct pcl_arr
{
std::array<T, N> d;
explicit constexpr pcl_arr()
: d{}
{
for (size_t i{}; i < N; d[i] = !i ? 0. : F(pi + i).v, ++i);
}
};
int main()
{
using yummy = pcl_arr<10, long double, fun<long double>>;
constexpr yummy pies;
std::array cloned_pies{pies.d};
// long double comparison is unsafe
// it's just for the sake of example
static_assert(pies.d[0] == 0.);
for (const auto & pie : pies.d) { std::cout << pie << ' '; } std::cout << '\n';
for (const auto & pie : cloned_pies) { std::cout << pie << ' '; } std::cout << '\n';
return 0;
}
godbolt.org x86-x64 gcc 11.2 -Wall -O3 -std=c++20 output:
0 17.1528 26.436 37.7192 51.0023 66.2855 83.5687 102.852 124.135 147.418
0 17.1528 26.436 37.7192 51.0023 66.2855 83.5687 102.852 124.135 147.418