I have a function which takes several boolean template arguments:
template<bool par1, bool par2, bool par2>
void function(int arg1, int arg2, int arg3);
I want to generate automatically at compile-time (with whatever template magic, with C++11 if needed) a table (or something equivalent as in the funny structures of C++ metaprogramming) of the function pointers to all the combination of the values of the template parameters par*
, so that I can construct a function which takes these template parameters as runtime arguments and forward to the right template instantiation:
void runtime_function(bool par1, bool par2, bool par3, int arg1, int arg2, int arg3);
I think that this can be done if instead of a template function one wanted to do the same with classes, thanks to template template arguments:
template<template<bool> class T> class CombinationsOfTemplateParameters;
template<template<bool, bool> class T> class CombinationsOfTemplateParameters;
template<template<bool, bool, bool> class T> class CombinationsOfTemplateParameters;
//and so on, up to some implementation defined hard limit.
But as far as I know there's no way to point to a generic template function, leaving its template parameters unspecified. Hence I don't know how to pass it to some helper class in its template parameter list, in the first place.
Is there a way to solve this problem?
Step one, just to understand the problem, I would construct an array of function pointers with each instantiation:
Notice how that looks like a table of 3-bit binary numbers:
So you can index into the array with an integer formed by bitwise operations:
Step two, now that I've understood how to construct the array and use it, I would generate the array automatically with a variadic template, instead of writing it out by hand.
First use a type that creates a parameter pack of integers (using Johannes Schaub's
seq
template):Then use that in a pack expansion to generate each possible instantiation:
Now you can use that like so:
The magic number
8
is two to the power of three (the number of bool parameters.)Step three, test it. I'm fairly confident it wouldn't even have compiled if I got the core logic wrong, as all the types and pack expansions will be checked by the compiler, but I could have got the bitwise operations wrong.
It prints:
Fully generic version
To do it for a function template with four bool template parameters you'd need to use
gens<16>
and change the pack expansionThis isn't very convenient, so it should be possible to generalise it to handle any number of parameters, by introducing another parameter pack of ints
seq<3,2,1,0>
and using it like:But this won't work, because we want a pack expansion using
Bits
but we don't want it to expandN
at the same time (and the packs have different sizes so it woulodn't work anyway,) so we need to use a level of indirection to allow the packs to be expanded separately.The final version below uses a function
gen_func<N>
to get the function pointer at index N:And adds
genrevs
to create a reverse sequence of integers,seq<2,1,0>
, which is passed to that function to be used as theMask
parameter pack:With that change the
make_table
class template can handle functions with any arity, so the final step is to parameterise it by the function type (and have it deduce the number of parameters, and from that the number of possible function specializations) and to add an accessor tomake_table
to get the right function:Here's the full final version. After writing this code last night I realised it assumes that the number of function parameters
(int, int, int)
is the same as the number of template parameters<bool, bool, bool>
, if that's not true then you'd need to add an extra non-type template parameter tomake_table
, specifying the number of template parameters (in the code below that'sNParams
and is deduced):