Recreate function signature and call via template packs in C++ - 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

Related

Looping over a templated C++ function with int type

Is there a solution like this to loop over a function with a templated int parameter that doesn't require creating a new struct with a body() function any time forIdx is needed with a new function? Templated lambdas in C++20 seemed promising, but it didn't seem possible to specify template parameters that aren't automatically deduced.
struct LoopFunc {
template <int i>
void body() {
std::cout << i;
};
};
template<int i>
struct forIdx {
template<typename T>
static void loop(T&& func) {
func.body<i>();
forIdx<i - 1>::loop(func);
}
};
template<>
struct forIdx<-1> {
template<typename T>
static void loop(T&& func) {};
};
int main() {
forIdx<10>::template loop(LoopFunc{});
}
The function is used to create a cartesian product of tuple elements. DirectProduct contains elements that all have a static generateAllElements() function.
struct CrossProduct {
std::tuple<MockElement...> vals;
std::set<DirectProduct> result;
template <int num>
void body() {
if (result.empty()) {
for (const auto& e2 : std::get<num>(vals).generateAllElements()) {
DirectProduct tmp;
std::get<num>(tmp.vals) = e2;
result.insert(tmp);
}
}
else for (const DirectProduct& e1 : result)
for (const auto& e2 : std::get<num>(vals).generateAllElements()) {
DirectProduct tmp = e1;
std::get<num>(tmp.vals) = e2;
result.insert(tmp);
}
};
};
DirectProduct uses the CrossProduct in its own generateAllElements() function
std::set<DirectProduct> generateAllElements() const {
CrossProduct crossProduct{ };
forIdx<std::tuple_size<std::tuple<MockElement...>>::value - 1>::template loop(crossProduct);
return crossProduct.result;
};
"Templated lambdas in C++20" have you said?
Do you mean something as follows?
#include <iostream>
#include <type_traits>
template <std::size_t I>
void loop_func()
{ std::cout << I << ' '; };
int main ()
{
[]<std::size_t ... Is>(std::index_sequence<Is...>)
{ (loop_func<sizeof...(Is)-Is-1u>(), ...); }
(std::make_index_sequence<11u>{});
}
That prints
10 9 8 7 6 5 4 3 2 1 0
template<auto x>
using value_t=std::integral_constant<std::decay_t<decltype(x)>,x>;
template<auto x>
constexpr value_t<x> value={};
template<std::size_t...Is>
using indexes_t=std::tuple<value_t<Is>...>;
template<std::size_t>
constexpr indexes_t<Is...> indexes={};
some compile time values.
template<std::size_t N>
constexpr auto indexes_upto=[]<std::size_t...Is>(std::index_sequence<Is...>){ return indexes<Is...>; }( std::make_index_sequence<N>{} );
now we are almost done.
void do_foreach_arg(auto f){
return [&](auto&&...args){
((void)(f(std::forward<decltype(args)>(args))),...);
};
}
template<std::size_t N>
auto do_foreach_index_upto( auto f ){
std::apply( do_foreach_arg(std::move(f)), indexes_upto<N> );
}
your main now looks like
do_foreach_index_upto<N>([](auto I){ LoopFunc{}.body<I>(); });
but the LoopFunc class is really not needed. You can just call some_func<I>() directly.
What we do here is we make stateless compile time values representing the integers up to 10. We stuff them in a tuple, unpack them with std apply, and unpack that with do_foreach_arg.
We could probably skip the tuple "step" here, but more advanced use could find it useful.

How to write a variadic-template function with objects as parameters?

Consider the following functions (it uses the CSV parser library from ben-strasser (github))
void col1(const std::string &fn, Base *v0)
{
io::CSVReader<2> in(fn);
in.read_header(io::ignore_extra_column, "epoch", v0->column);
double ign;
while (in.read_row(ign, v0->value)) {
v0->process();
}
}
void col2(const std::string &fn, Base *v0, Base *v1)
{
io::CSVReader<3> in(fn);
in.read_header(io::ignore_extra_column, "epoch", v0->column, v1->column);
double ign;
while (in.read_row(ign, v0->value, v1->value)) {
v0->process();
v1->process();
}
}
This function processes the value in column 2 of a CSV-file. v0 of type Base * contains the member value which is filled by read_row and is processed in the process-method. Base is an interface-class of calculation methods (for exemple: one is Max, another one is MinMaxAvg).
How could I rewrite this function to accept any number of Base * arguments in order to process multiple columns?
read_header and read_row are variadic-template function and thus can accept any number of arguments, but they only work with scalars.
How do I expand/unpack the variadic-argument so that it calls or uses a member?
I tried some things, reading some examples, but I'm unable to create something which works, here is my current/ridicules code:
template<unsigned int COL>
void func(const std::string &fn, Base &... values)
{
io::CSVReader<COL> in(fn);
// that's it :-(
}
Some well-placed pack expansions will work dandy:
template <class... Bases>
void col(const std::string &fn, Bases *... bases)
{
io::CSVReader<sizeof...(Bases) + 1u> in(fn);
in.read_header(io::ignore_extra_column, "epoch", bases->column...);
double ign;
while (in.read_row(ign, bases->value...)) {
// Awful C++11 arbitrary expansion trick
int dum[]{ 0, (void(
bases->process()
), 0)... };
(void) dum;
// Alternative, sweet and beautiful C++17 fold expression
// (void)(bases->process(), ...);
}
}
Two steps: first, we need to extend our function as desired:
template <typename ... Bases>
void f(std::string const& s, Bases* ... values)
{
io::CSVReader<sizeof...(Bases) + 1> in(s);
in.read_header(io::ignore_extra_column, "epoch", values->column ...);
double ign;
while(in.read_row(ign, values->value ...))
{
/* see below! */ process(values...);
}
}
So far no problem, read_header and read_row are variadic templates, so fine. Calling the member function was a little tricky, however - have a look at the call to the (yet unknown) process function above. Keyword compile time recursion (101010's answer), here we go:
void process()
{ }
template <typename ... Bases>
void process(Base* b, Bases* ... values)
{
b->process();
process(values ...);
}
Define these two functions before the template function, and it works...
Edit: Stealing sizeof...(Bases) + 1 from J.Doe...
Use pack expansion operator ... to unpack your variadic arguments.
template<typename... T> void nop(T&&...) { }
template<typename... Bases>
void func(const std::string &fn, Bases&&... bases)
{
io::CSVReader<sizeof...(Bases) + 1> in(fn);
in.read_header(io::ignore_extra_column, "epoch", bases->column...);
double ign;
while (in.read_row(ign, bases->value...)) {
// multiple ways to call process on all values
// prettier with C++17 stuff it seems
nop((bases->process(), 0)...);
}
}
With variadic templates you must materialize some short of compile time recursion:
template<unsigned int COL>
void func(const std::string &fn, Base &v) {
...
}
template<unsigned int COL, typename... Args>
void func(const std::string &fn, Base &v, Args&&... args) {
...
func<COL>(fn, std::forward<Args>(args)...);
}
compilable example (you will need to fill in the code for reading from the csv file and writing to each target):
#include <string>
#include <cstdint>
#include <utility>
#include <tuple>
template<class Function, class...Ts>
void for_all(Function f, Ts&&...ts)
{
using expand = int[];
void(expand{0,
(f(std::forward<Ts>(ts)), 0)...
});
}
// some mocked io library
namespace io
{
template<std::size_t MaxRows>
struct CSVReader
{
CSVReader(const std::string& s)
{
}
template<class...Targets>
void read_headers(std::tuple<Targets...>& target)
{
read_headers_impl(std::make_index_sequence<sizeof...(Targets)>(), target);
}
template<class...Targets>
void read_row(std::tuple<Targets...>& targets)
{
read_values_impl(std::make_index_sequence<sizeof...(Targets)>(), targets);
}
// support for std::tie
template<class...Targets>
void read_row(const std::tuple<Targets...>& targets)
{
read_values_impl(std::make_index_sequence<sizeof...(Targets)>(), targets);
}
private:
template<std::size_t...Is, class Tuple>
void read_headers_impl(std::index_sequence<Is...>, Tuple& target)
{
for_all([](auto&& target) {
// read the header and assign it to target here
}, std::get<Is>(target)...);
}
template<std::size_t...Is, class Tuple>
void read_values_impl(std::index_sequence<Is...>, Tuple& target)
{
for_all([](auto&& target) {
// read the values and assign it to target here
}, std::get<Is>(target)...);
}
};
}
struct Base
{
std::string& value();
void process();
};
template<std::size_t N, class T, class Current = std::tuple<>> struct n_tuple;
template<std::size_t N, class T> using n_tuple_t = typename n_tuple<N, T>::type;
template<std::size_t N, class T, class Current>
struct n_tuple
{
using type = std::conditional_t<
N == std::tuple_size<Current>::value,
Current,
decltype(std::tuple_cat(std::declval<Current>(), std::declval<n_tuple_t<N-1, T>>()))
>;
};
template<class...Bases>
void col_n(const std::string &fn, Bases&...bases)
{
constexpr std::size_t column_count = sizeof...(Bases) + 1;
io::CSVReader<column_count> in(fn);
using headers_type = n_tuple_t<column_count, std::string>;
auto headers = headers_type();
in.read_headers(headers);
double ign;
auto value_refs = std::tie(ign, bases.value()...);
while (in.read_row(value_refs)) {
// now we only want to process each base
for_all([](auto&& base) {
base.process();
}, bases...);
}
}

C++ template instantiation: Avoiding long switches

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

Get type for index in tuple during runtime

I know, there are several topic, asking very close things but I don't get it to work in my case.
I would like to build a templated factory with index access during runtime. Therefore I have several types with the same base type. The factory gets the types which it is able to procude per template parameters. The call to the factory just gives an index. This is a small example:
#include <iostream>
#include <memory>
#include <tuple>
struct Base {
};
struct A : Base {
A(int) { std::cout << "A" << std::endl; }
};
struct B : Base {
B(int) { std::cout << "B" << std::endl; }
};
struct C : Base {
C(int) { std::cout << "C" << std::endl; }
};
template <typename ... Types>
struct Factory {
typedef std::tuple<Types...> TypesTuple;
std::shared_ptr<Base> operator ()(int index) {
return produce(index);
}
std::shared_ptr<Base> produce(int index) {
switch (index) {
case 0: return std::make_shared<typename std::tuple_element<0, TypesTuple>::type>(42);
case 1: return std::make_shared<typename std::tuple_element<1, TypesTuple>::type>(42);
}
throw;
}
};
//==============================================================================
int main() {
Factory<A, C> factory_ac;
auto a1 = factory_ac(0);
auto c1 = factory_ac(1);
Factory<A, B, C> factory_bc;
auto a2 = factory_bc(0);
auto b2 = factory_bc(1);
auto c2 = factory_bc(2);
}
I tried to overload the produce method with
template <typename = typename std::enable_if<std::tuple_size<TypesTuple>::value==2>::type>
counting up the size and providing the respective switch statements, but this does not compile, overload not allowed.
I tried using https://stackoverflow.com/a/7383493/2524462 but I couldn't get it to work, because the parameter packs don't expand with a lambda and wrapping it in a template function I get problems with the constexpr array, since I don't have trivial types.
Boost MPL for_eachcomes to mind, but I got problems compiling, because my types are not trivially constructable.
So how would one change the factory to get the main to compile and work?
It seems this can be done quite straight forward:
template <typename T>
std::shared_ptr<Base> make() {
return std::make_shared<T>();
}
template <typename... T>
class Factory {
public:
std::shared_ptr<Base> operator()(int index) {
static constexpr std::shared_ptr<Base> (*factories[])() = {
&make<T>...
};
if (index < 0 && sizeof...(T) <= index) {
throw std::range_error("type index out of range");
}
return (factories[index])();
}
};
I'm currently not in the position to compile the code but something along this lines should work: the idea is to create an array of factory functions and just call into this array.
If I have understood your requirements correctly, I think this does what you want:
template<int... Is>
struct indices { typedef indices type; };
template<int N, int... Is>
struct make_indices : make_indices<N - 1, N - 1, Is...> { };
template<int... Is>
struct make_indices<0, Is...> : indices<Is...> { };
template<typename... Types>
struct Factory
{
typedef std::tuple<Types...> TypesTuple;
std::shared_ptr<Base> operator()(int const index)
{
return produce(index);
}
std::shared_ptr<Base> produce(int const index)
{
return produce_impl(make_indices<sizeof...(Types)>(), index);
}
template<int I, int... Is>
std::shared_ptr<Base> produce_impl(indices<I, Is...>, int const index)
{
if (I == index) {
return std::make_shared<typename std::tuple_element<I, TypesTuple>::type>(42);
}
return produce_impl(indices<Is...>(), index);
}
std::shared_ptr<Base> produce_impl(indices<>, int const index)
{
throw "Uh-oh!";
}
};
See output here.

c++0x: overloading on lambda arity

I'm trying to create a function which can be called with a lambda that takes either 0, 1 or 2 arguments. Since I need the code to work on both g++ 4.5 and vs2010(which doesn't support variadic templates or lambda conversions to function pointers) the only idea I've come up with is to choose which implementation to call based on arity. The below is my non working guess at how this should look. Is there any way to fix my code or is there a better way to do this in general?
#include <iostream>
#include <functional>
using namespace std;
template <class Func> struct arity;
template <class Func>
struct arity<Func()>{ static const int val = 0; };
template <class Func, class Arg1>
struct arity<Func(Arg1)>{ static const int val = 1; };
template <class Func, class Arg1, class Arg2>
struct arity<Func(Arg1,Arg2)>{ static const int val = 2; };
template<class F>
void bar(F f)
{
cout << arity<F>::val << endl;
}
int main()
{
bar([]{cout << "test" << endl;});
}
A lambda function is a class type with a single function call operator. You can thus detect the arity of that function call operator by taking its address and using overload resolution to select which function to call:
#include <iostream>
template<typename F,typename R>
void do_stuff(F& f,R (F::*mf)() const)
{
(f.*mf)();
}
template<typename F,typename R,typename A1>
void do_stuff(F& f,R (F::*mf)(A1) const)
{
(f.*mf)(99);
}
template<typename F,typename R,typename A1,typename A2>
void do_stuff(F& f,R (F::*mf)(A1,A2) const)
{
(f.*mf)(42,123);
}
template<typename F>
void do_stuff(F f)
{
do_stuff(f,&F::operator());
}
int main()
{
do_stuff([]{std::cout<<"no args"<<std::endl;});
do_stuff([](int a1){std::cout<<"1 args="<<a1<<std::endl;});
do_stuff([](int a1,int a2){std::cout<<"2 args="<<a1<<","<<a2<<std::endl;});
}
Be careful though: this won't work with function types, or class types that have more than one function call operator, or non-const function call operators.
I thought the following would work but it doesn't, I'm posting it for two reasons.
To save people the time if they had the same idea
If someone knows why this doesn't work, I'm not 100% sure I understand (although I have my suspicions)
Code follows:
#include <iostream>
#include <functional>
template <typename Ret>
unsigned arity(std::function<Ret()>) { return 0; }
template <typename Ret, typename A1>
unsigned arity(std::function<Ret(A1)>) { return 1; }
template <typename Ret, typename A1, typename A2>
unsigned arity(std::function<Ret(A1, A2)>) { return 2; }
// rinse and repeat
int main()
{
std::function<void(int)> f = [](int i) { }; // this binds fine
// Error: no matching function for call to 'arity(main()::<lambda(int)>)'
std::cout << arity([](int i) { });
}
Compile time means of obtaining the arity of a function or a function object, including that of a lambda:
int main (int argc, char ** argv) {
auto f0 = []() {};
auto f1 = [](int) {};
auto f2 = [](int, void *) {};
std::cout << Arity<decltype(f0)>::value << std::endl; // 0
std::cout << Arity<decltype(f1)>::value << std::endl; // 1
std::cout << Arity<decltype(f2)>::value << std::endl; // 2
std::cout << Arity<decltype(main)>::value << std::endl; // 2
}
template <typename Func>
class Arity {
private:
struct Any {
template <typename T>
operator T ();
};
template <typename T>
struct Id {
typedef T type;
};
template <size_t N>
struct Size {
enum { value = N };
};
template <typename F>
static Size<0> match (
F f,
decltype(f()) * = nullptr);
template <typename F>
static Size<1> match (
F f,
decltype(f(Any())) * = nullptr,
decltype(f(Any())) * = nullptr);
template <typename F>
static Size<2> match (
F f,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr);
public:
enum { value = Id<decltype(match(static_cast<Func>(Any())))>::type::value };
};
This way works:
template<typename F>
auto call(F f) -> decltype(f(1))
{
return f(1);
}
template<typename F>
auto call(F f, void * fake = 0) -> decltype(f(2,3))
{
return f(2,3);
}
template<typename F>
auto call(F f, void * fake = 0, void * fake2 = 0) -> decltype(f(4,5,6))
{
return f(4,5,6);
}
int main()
{
auto x1 = call([](int a){ return a*10; });
auto x2 = call([](int a, int b){ return a*b; });
auto x3 = call([](int a, int b, int c){ return a*b*c; });
// x1 == 1*10
// x2 == 2*3
// x3 == 4*5*6
}
It works for all callable types (lambdas, functors, etc)