Lazy initialization of a static member array of a template class - c++

I am writing code to perform Gaussian integration with n points, where n is a compile time constant.
For a given n, I know how to compute abscissas and weights. The computation has to be done from scratch for each different n.
Now, I do something along these lines:
// Several structs like this one (laguerre, chebyshev, etc).
template <size_t n>
struct legendre
{
static const size_t size = n;
static const double x[n];
static const double w[n];
};
template <typename Rule, typename F>
double gauss_quadrature (F&& f)
{
double acc = 0;
for (size_t j = 0; j < Rule::size; j++)
acc += Rule::w[j] * f (Rule::x[j]);
return acc;
}
to be used like this:
double i = gauss_quadrature<legendre<12>> (f);
Now, I can specialize in a translation unit the coefficients for legendre<12>, by doing
template <>
const legendre<12>::x[12] = { ... };
template <>
const legendre<12>::w[12] = { ... };
and everything is fine, as long as I only use 12-points Gauss-Legendre.
Now, I'm experimenting with different number of points, and I know how to generate the weights and nodes. I can for instance provide a routine
void compute_legendre_coeffs (size_t n, double* w, double* x);
and :
When I call gauss_quadrature<legendre<n>>, the template legendre<n> is automatically instantiated (this is the case).
When legendre<n> is instantiated for some compile-time n, I'd like the above compute_legendre_coeffs to be called at some point before main so that it fills the x and w member arrays. How do I achieve this ?
I know must define the arrays first:
template <size_t n>
const double legendre<n>::x[n] = {};
template <size_t n>
const double legendre<n>::w[n] = {};
but I can't come up with a method to initialize them. Anyone has a trick to do so ?

Convert the arrays to std::array:
#include <array>
template<int n> struct legendre {
static const std::array<double, n> x;
};
void compute_xs(int n, double *xs) {
...
}
template<int n> std::array<double, n> make_xs() {
std::array<double, n> xs;
compute_xs(n, xs.data());
return xs;
}
template<int n> const std::array<double, n> legendre<n>::x = make_xs<n>();
This does mean computing the x and w coefficients separately, though there are workarounds if this is less efficient, for example:
template<int n> struct legendre_coeffs {
std::array<double, n> x, w;
legendre_coeffs(): x(), w() { compute_legendre_coeffs(n, w.data(), x.data()); }
};
template<int n> struct legendre {
static const legendre_coeffs coeffs;
static const double (&x)[n], (&w)[n];
};
template<int n> const legendre_coeffs legendre<n>::coeffs;
template<int n> const double (&legendre<n>::x)[n]
= *reinterpret_cast<const double (*)[n]>(legendre<n>::coeffs::x.data());
template<int n> const double (&legendre<n>::w)[n]
= *reinterpret_cast<const double (*)[n]>(legendre<n>::coeffs::w.data());

template <size_t n>
class legendre
{
public:
static const size_t size = n;
static const double (&getX())[n] {
init();
return x;
}
static const double (&getW())[n] {
init();
return x;
}
private:
static double x[n];
static double w[n];
static void init() {
static bool _ = do_init(x,y);
}
static bool do_init( double *x, double *y ) {
// do the computation here, use local vars x, y
return true;
}
};
template <size_t n>
double legendre<n>::x[n];
template <size_t n>
double legendre<n>::w[n];
By providing an accessor you gain control of the entry point to your class. The accessors dispatch to a init function that uses initialization of a local static variable to call do_init only once in the program lifetime. The do_init does the actual initialization of the members.
Notes:
Depending on the compiler, this might not be thread safe (i.e. not all C++03 compilers provide thread safe initialization of static variables, which in turn means that the do_init might be called more than once in parallel, depending on the algorithm that might or not be an issue --i.e. if do_init computes the values aside and just writes them, the potential race condition is irrelevant as the net result will be the same). Some compilers offer mechanisms to guarantee one off execution (I believe boost has such a mechanism). Alternatively depending on your domain, you might be able to prime the coefficients before you start the threads.
The actual arrays cannot be const in this case, as the initialization needs to happen after they are created. That should not be an issue for anything other than possible micro optimizations (i.e. the compiler does not know about the values of the coefficients, so it cannot perform sub-expression evaluation at compile time).

First of all: you can't do initialization completely at compile-time using C++03 (yep, by design!) -- the only way to do it is to use C++ templates, but you'll unable to pass a double as template parameter.
Things getting better w/ C++11 -- you may use constexpr but only if your compute_legendre_coeffs() is trivial enough.
Or there is one trick I use when need to take some actions by fact of class declaration -- for example, register smth somewhere... to provide serialization capabilities via some library or smth like this.
You may use static constructors idiom to initalize that arrays... For simialr reasons I use the following code:
template <
typename Derived
, typename Target = Derived
>
class static_xtors
{
// This class will actually call your static init methods...
struct helper
{
helper()
{
Target::static_ctor();
}
~helper()
{
Target::static_dtor();
}
};
// ... because your derived class would inherit this member from static_xtor base
static helper s_helper;
// The rest is needed to force compiler to instantiate everything required stuff
// w/o eliminate as unused...
template <void(*)()>
struct helper2 {};
static void use_helper()
{
(void)s_helper;
}
helper2<&static_xtors::use_helper> s_helper2;
virtual void use_helper2()
{
(void)s_helper2;
}
public:
/// this is not required for your case... only if later you'll have
/// a hierarchy w/ virtuals
virtual ~static_xtors() {}
};
template <
typename Derived
, typename Target
>
typename static_xtors<Derived, Target>::helper
static_xtors<Derived, Target>::s_helper;
then you have to inherit static_xtors class, and implement two static methods: void static_ctor() -- which would initialize your arrays, and empty (in your case) void static_dtor()... I.e. smth like this:
template <size_t n>
struct legendre : public static_xtors<legendre<n>>
{
static const size_t size = n;
static double x[n];
static double w[n];
static void static_ctor()
{
compute_legendre_coeffs(n, x, w);
}
static void static_dtor()
{
// nothing to do
}
};
template <size_t n>
static double legendre<n>::x[n];
template <size_t n>
static double legendre<n>::w[n];
As you may notice, x and w is not const anymore :( -- you may try to make them const again hiding to private and add static getters to be used by callers... Also, your internal arrays would be initialized at runtime, but before the main function (and just once)...
or play w/ constexpr... but seems you'll need to redesign you initializer function (somehow) because using initialization lists it should looks like this:
template <size_t n>
static double legendre<n>::x[n] = { calc_coeff_x<0>(), calc_coeff_x<1>(), calc_coeff_x<2>(), ... }
... and definitely you can't do it w/o specializing (and extensive macros usage).
But probably variadic templates may help... need to know more details about your function and time to think :))

Maybe you can try turning your function into an initializer class template, whose parameter would be the class/struct you want to initialize. Then change that class template to include a constant instance of the initializer . Finally, have the constructor of the initializer class trigger the code doing the actual initialization.
You should perhaps also protect access [1] to the initializer class so that the initialization doesn't happen more than once.
The idea, as you can see, is to use the facts that class instances get their constructor code called, template instances get their constant data initialized.
Below is a possible (and simple) implementation, without template:
struct legendre_init {
legendre_init(){
compute_legendre_coeffs (T::n, T::w, T::x);
}
};
template <size_t n>
struct legendre
{
typedef legendre<n> self_type;
static const size_t size = n;
static const double x[n];
static const double w[n];
static const legendre_init _l;
};
Here's another take on it, this time putting the initialization in the struct directly:
template <class T>
class T_init {
public:
T_init(){
T::_init();
}
};
template <size_t n>
struct legendre
{
typedef legendre<n> self_type;
static const size_t size = n;
static const double x[n];
static const double w[n];
static const T_init<self_type> _f;
static void _init(){
compute_legendre_coeffs (self_type::n, self_type::w, self_type::x);
}
};
The interesting characteristic of this solution is that the T_init constant instance shouldn't take any space within the T struct. The initialization logic is bundled with the class that needs it, and the T_init template only enables it automatically.
[1] Xeo mentioned the std::call_once template, which could come handy here.

Related

How to disable a member function based on a class template parameter?

To illustrate the situation, let's assume a minimal example: a Vector template class taking its dimension as a non-type template parameter. This class will provide x(), y() (etc.) accessors when the dimension allows it:
template <int N_dimension>
class Vector
{
public:
// ctors, etc.
int &x();
template <class = std::enable_if_t<(N_dimension>2)>> int &y();
private:
std::array<int, N_dimension> mData;
};
Yet, this does not work, because enable_if can only be applied on deduced template parameters.
Our current workaround looks cumbersome:
template <int N=N_dimension, class = std::enable_if_t<(N>2)>> int &y();
Moreover, it also requires a static-assert in the definition to make sure it is fool-proof (because now client code could give an explicit value to N that does not match the real dimension. Edit: Or an explicit value for the anonymous second template parameter, as pointed out by SergeyA).
Is there a more direct approach to express this in C++?
I would do away with SFINAE here, and simply split the code into interface and private implementation like that:
int& y() {
return y_impl(std::bool_constant<N > 2>{});
}
private:
int& y_impl(std::true_type ) {
// impl
}
int& y_impl(std::false_type ) {
static_assert(N > 2 /* always false */, "Wrong number of dimensions!");
}
The split here is in assumption of y not compilable when N <= 2, to reduce the clutter of error messages. If this is not the case, a single static_assert in y body would be sufficient.
In C++20, you might simply use requires to discard method:
template <int N>
class Vector
{
public:
int &x();
int &y() requires(N >= 2);
private:
std::array<int, N_dimension> mData;
};
In previous version, it is more verbose:
template <std::size_t N>
class Vector
{
public:
int &x();
template <std::size_t M = N, std::enable_if_t<(M >= 2 && M == N), int> = 0>
int &y();
private:
std::array<int, N_dimension> mData;
};

Multidimensional array with dynamic extents (without raw pointers)

The rationale behind said array is to emulate a 2D/3D pixel matrix.
After doing a fair amount of research and reading, I reckon Boost.MultiArray might come in handy for this. However, I still have to create a neat wrapper on top of it to allow for less verbose coding.
Ultimately, what I want to achieve is the following:
PixMat<u8, 3, {2, 4, 3}> pixMat;
or
PixMat<u8, 3> pixMat(2,3,4);
, which would basically create a 2x4x3 matrix of u8 values.
What I've come up with so far is:
template <typename T, int Dims>
class PixMat {
public:
typedef typename boost::multi_array<T, Dims> PixMatType;
typedef typename PixMatType::index PixMatTypeIdx;
PixMat(int dim1Ext, int dim2Ext) : pixMat(PixMatType(boost::extents[dim1Ext][dim2Ext])) {}
PixMat(int dim1Ext, int dim2Ext, int dim3Ext) : pixMat(PixMatType(boost::extents[dim1Ext][dim2Ext][dim3Ext])) {}
private:
PixMatType pixMat;
};
template <typename T>
class Pix2DMat : PixMat<T, 2> {
public:
Pix2DMat(int dim1Ext, int dim2Ext) : PixMat<DataType, 2>(dim1Ext, dim2Ext) {}
};
template <typename T>
class Pix3DMat : PixMat<T, 3> {
public:
Pix3DMat(int dim1Ext, int dim2Ext, int dim3Ext) : PixMat<DataType, 3>(dim1Ext, dim2Ext, dim3Ext) {}
};
I'm not too keen on this solution. Normally, the matrix won't be either 2D or 3D, but still, I'd like a more generic solution.
Questions:
Is there a way to provide the extents of the dimensions as template arguments as well instead of via C-TOR?
Is there a better way than inheritance to achieve this e.g. template specialization, variadic templates? But then how to deal with not duplicating the typedefs for boost all over the place?
Here are a few techniques that I think you could use:
Variadic constructor argument
Rather than having a separate constructor for each possible dimension, you could use variadic argument techniques to create a generic N-dimensional constructor. Something that is your friend here: boost::extents is not required for the constructor argument, but instead anything that meets the requirements of a Collection. One example is just a plain STL or boost array:
template <typename... DimSizes>
PixMat(DimSizes&&... sizes)
: pixMat(boost::array<std::size_t, sizeof...(DimSizes)>{{ static_cast<size_t>(sizes)...}}) {
}
This isn't the most polished implementation; in particular it doesn't place much of a requirement on DimSizes, which should really all be the same unsigned integer type (see this question for possible improvements). Also (for simplicity) perfect forwarding isn't implemented, but that probably just requires wrapping sizes with std::forward<DimSizes>(sizes) in the constructor.
You can consult this stackoverflow post for possible alternative implementations.
Static assertion / SFINAE
Your template base class has a 2D constructor and 3D constructor --- or if you follow the above, a template N-dimensional constructor --- regardless of the value of the actual template parameter. You could use static assertion or SFINAE so that only the the Dims-D dimensional constructor is compilable. This will convert run-time bugs into compilation errors:
template <typename... DimSizes>
PixMat(DimSizes&&... sizes)
: pixMat(boost::array<std::size_t, sizeof...(DimSizes)>{{ static_cast<size_t>(sizes)...}}) {
static_assert(sizeof...(DimSizes) == Dims);
}
Dimension sizes as templates
I think this is a possible though completely orthogonal solution. It's implementation would follow from the above without too much work, but to make this interoperable with the constructor argument based solution would require a lot of hard work (i.e. to make them part of the same class or class hierarchy).
Other libraries
You might want to take a look at Eigen, for example. It does a lot of the aforementioned hard work.
If I understood you correctly, you want compile-time dimension, but run-time extents.
I would use a design like this:
template <typename T,std::size_t Dim>
class mdvector
{
private:
std::vector<T> Data;
std::array<std::size_t,Dim> Extents;
private:
std::size_t Offset(std::size_t const Sum) const
{ return Sum; }
template <typename... IndexType>
std::size_t Offset(std::size_t const Sum,std::size_t const Index,IndexType const... Indices) const
{ return Offset(Sum*Extents[Dim-sizeof...(Indices)-1u]+Index,Indices...); }
public:
template <typename... IndexType,typename= std::enable_if_t<sizeof...(IndexType)==Dim>>
mdvector(IndexType const... Indices):
Data((... * Indices)), // c++17 fold expression
Extents{Indices...} {}
template <typename... IndexType,typename= std::enable_if_t<sizeof...(IndexType)==Dim>>
T const &operator()(IndexType const... Indices) const
{ return Data[Offset(0u,Indices...)]; }
template <typename... IndexType,typename= std::enable_if_t<sizeof...(IndexType)==Dim>>
T &operator()(IndexType const... Indices)
{ return Data[Offset(0u,Indices...)]; }
};
The data are stored in a std::vector while the extents make up an std::array.
Since I assume you want multi-dimensional access I have used a given mapping via the recursive function Offset. You have quite freedom in this regard.
Here's an example of use:
int main()
{
mdvector<double,3u> myvec(2u,3u,4u);
for (int i= 0; i<2; ++i)
for (int j= 0; j<3; ++j)
for (int k= 0; k<4; ++k)
myvec(i,j,k)= i;
for (int k= 0; k<4; ++k)
{
for (int i= 0; i<2; ++i)
{
for (int j= 0; j<3; ++j)
std::cout << myvec(i,j,k) << "\t";
std::cout << "\n";
}
std::cout << "\n";
}
}
Since the extents are dynamic, you can change them at runtime, for example:
template <typename T,std::size_t Dim>
template <typename... IndexType,typename= std::enable_if_t<sizeof...(IndexType)==Dim>>
void mdvector<T,Dim>::Resize(IndexType const... Indices)
{ Data.resize((... * Indices)); Extents= {Indices...}; }
If, on the other hand, you prefer the extents to be template parameters, they should stay fixed at runtime. In that case, you would include them in the class declaration:
template <typename T,std::size_t... Indices>
class mdvector { /* ... */};
but the implementation would be pretty much the same. Note that specifying the dimension would be unnecessary since you can get it with sizeof...(Indices).
The fold expression in the above code is not estrictly necessary. An equivalent outcome is achieved with:
static constexpr std::size_t Product()
{ return 1u; }
template <typename... IndexType>
static constexpr std::size_t Product(std::size_t const Index,IndexType const... Indices)
{ return Index*Product(Indices...); }
template <typename... IndexType,typename= std::enable_if_t<sizeof...(IndexType)==Dim>>
mdvector(IndexType const... Indices):
Data(Product(Indices...)), Extents{Indices...} {}

Function array initialization at compile time with metaprograming

In video-games is common that resources are loaded in a step fashion way, so within a single thread a loading bar can update at each loading step. By example:
1 -> Load texture A
2 -> Update Loading Bar to 2%
3 -> Load texture B
4 -> Update Loading Bar to 4%
5 ...
This can be done in many ways. One of these is define a function for each loading step.
void LoadTextureA()
{
//Loading routine
...
}
This has the advantage of readability, not need too much nested code and even possible in some cases to share loading routines between two game states.
Now what I was thinking was to generalize this "function-for-step" model with templates. Lets say.
template <int S>
struct Foo{
void LoadingStep()
{
}
};
template <>
struct Foo<0>
{
void LoadingStep()
{
//First loading step
...
}
};
Please correct me if I'm wrong. But it appears possible that I can compile-time iterate through 0 .. to N steps using metaprogramming and assign this specialized functions to an array or vector of function pointers.
N steps are known at compile time along with it respective functions.
Function pointer vector would be iterated like this:
template <int Steps>
class Loader {
public:
bool Load()
{
functionArray[m_step]();
if (++m_step == Steps)
return false; //End loading
else
return true;
}
private:
int m_step;
}
Is this possible? I know that that are easier ways to do it. But besides project requirments it's an interesting programming challenge
I achieved it based on Kal answer of a similar problem
Create N-element constexpr array in C++11
template <int S>
struct Foo{
static void LoadingStep()
{
}
};
template <>
struct Foo<0>
{
static void LoadingStep()
{
//First loading step
}
};
template<template<int S> class T,int N, int... Rest>
struct Array_impl {
static constexpr auto& value = Array_impl<T,N - 1, N, Rest...>::value;
};
template<template<int S> class T,int... Rest>
struct Array_impl<T,0, Rest...> {
static constexpr std::array<void*,sizeof...(Rest)+1> value = {reinterpret_cast<void*>(T<0>::LoadingStep),reinterpret_cast<void*>(T<Rest>::LoadingStep)...};
};
template<template<int S> class T,int... Rest>
constexpr std::array<void*,sizeof...(Rest)+1> Array_impl<T,0, Rest...>::value;
template<template<int S> class T,int N>
struct F_Array {
static_assert(N >= 0, "N must be at least 0");
static constexpr auto& value = Array_impl<T,N>::value;
F_Array() = delete;
F_Array(const F_Array&) = delete;
F_Array(F_Array&&) = delete;
};
Using example:
int main()
{
auto& value = F_Array< Foo ,4>::value;
std::cout << value[0] << std::endl;
}
This yields of void* array of pointers to template functions:
Foo<0>::LoadinStep()
Foo<1>::LoadinStep()
Foo<2>::LoadinStep()
Foo<3>::LoadinStep()
Foo<4>::LoadinStep()
Since Foo<1..3> are not specialized they will fall to Default LoadingStep function
Yes. It's possible. And if you use the template metaprogramming, you don't need to use a run time loop, but a recursive call to a template method:
#include <iostream>
// The template numerated methods
template <int S> struct Foo{static void LoadingStep(){}};
template <> struct Foo<0> {static void LoadingStep(){std::cout<<0;}};
template <> struct Foo<1> {static void LoadingStep(){std::cout<<1;}};
template <> struct Foo<2> {static void LoadingStep(){std::cout<<2;}};
// The loader template method
template <int Step>
void Loader()
{
Foo<Step>::LoadingStep();
Loader<Step-1>();
}
// Stopping rule
template <> void Loader<-1>(){}
int main()
{
Loader<2>();
}
If you want an array:
LoadingFunction functionArray[] = {Function0, Function1, Function2};
.....
for (int i = 0; i < nSteps; ++i)
RunStep(i, nSteps, Function[i]);
Or initialize an std container with it.
If you want templates, you could write
for (int i = 0; i < nSteps; ++i)
RunStep(i, nSteps, Function<i>);
except i in Function<i> must be a constant. So you have to do it with a templated recursive something:
template <int i, int NSteps> struct RunSteps
{
void Run()
{
RunStep(i, NSteps, Function<i>);
RunSteps<i+1, NSteps>::Run();
}
};
template <int NSteps> struct RunSteps<NSteps, NSteps>
{
void Run() {}
};
RunSteps<0, NSteps>::Run();
Compile-time iteration doesn't really exist. The for loop and the templated recursive something do exactly the same thing. The compiler is as capable of unrolling a loop, as of inlining a call.
It looks like there's very little to be gained from templatizing this stuff, and lots to lose.
It is not clear why you would want to put templated functions to an array at compile time, but here you go:
LoadingFunction functionArray[] = {Function<0>, Function<1>, Function<2>};
Now if you don't want to enumerate functions manually like that, it could be a bit of a challenge. It doesn't seem possible with either legacy C arrays or any of the std containers. Assuming you really need it, it's possible to write a custom container capable of such initialization.
template <template <int> class FunctionWrappper, int NFunctions>
class MyOptimizedFunctionArray {
// filling this space is left as an exercise
};

compile time loops

I would like to know if it is possible to have sort of compile time loops.
For example, I have the following templated class:
template<class C, int T=10, int B=10>
class CountSketch
{
public:
CountSketch()
{
hashfuncs[0] = &CountSketch<C>::hash<0>;
hashfuncs[1] = &CountSketch<C>::hash<1>;
// ... for all i until i==T which is known at compile time
};
private:
template<int offset>
size_t hash(C &c)
{
return (reinterpret_cast<int>(&c)+offset)%B;
}
size_t (CountSketch::*hashfuncs[T])(C &c);
};
I would thus like to know if I can do a loop to initialize the T hash functions using a loop. The bounds of the loops are known at compile time, so, in principle, I don't see any reason why it couldn't be done (especially since it works if I unroll the loop manually).
Of course, in this specific example, I could just have made a single hash function with 2 parameters (although it would be less efficient I guess). I am thus not interested in solving this specific problem, but rather knowing if "compile time loops" existed for similar cases.
Thanks!
Nope, it's not directly possible. Template metaprogramming is a pure functional language. Every value or type defined through it are immutable. A loop inherently requires mutable variables (Repeatedly test some condition until X happens, then exit the loop).
Instead, you would typically rely on recursion. (Instantiate this template with a different template parameter each time, until you reach some terminating condition).
However, that can solve all the same problems as a loop could.
Edit: Here's a quick example, computing the factorial of N using recursion at compile-time:
template <int N>
struct fac {
enum { value = N * fac<N-1>::value };
};
template <>
struct fac<0> {
enum { value = 1 };
};
int main() {
assert(fac<4>::value == 24);
}
Template metaprogramming in C++ is a Turing-complete language, so as long as you don't run into various internal compiler limits, you can solve basically any problem with it.
However, for practical purposes, it may be worth investigating libraries like Boost.MPL, which contains a large number of data structures and algorithms which simplify a lot of metaprogramming tasks.
Yes. Possible using compile time recursion.
I was trying with your code but since it was not compilable here is a modified and compiling exmaple:
template<class C, int T=10>
class CountSketch
{
template<int N>
void Init ()
{
Init<N-1>();
hashfuncs[N] = &CountSketch<C>::template hash<N>;
cout<<"Initializing "<<N<<"th element\n";
}
public:
CountSketch()
{
Init<T>();
}
private:
template<int offset>
size_t hash(C &c)
{
return 0;
}
size_t (CountSketch::*hashfuncs[T])(C &c);
};
template<>
template<>
void CountSketch<int,10>::Init<0> ()
{
hashfuncs[0] = &CountSketch<int,10>::hash<0>;
cout<<"Initializing "<<0<<"th element\n";
}
Demo. The only constraint of this solution is that you have to provide the final specialized version as, CountSketch<int,10>::Init<0> for whatever type and size.
You need a combination of boost::mpl::for_each and boost::mpl::range_c.
Note: This will result in run-time code and this is what you actually need. Because there is no way to know the result of operator& at compile time. At least none that I'm aware of.
The actual difficulty with this is to build a struct that is templated on an int parameter (mpl::int_ in our case) and that does the assignment when operator() is called and we also need a functor to actually capture the this pointer.
This is somewhat more complicated than I anticipated but it's fun.
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/copy.hpp>
// aforementioned struct
template<class C, class I>
struct assign_hash;
// this actually evaluates the functor and captures the this pointer
// T is the argument for the functor U
template<typename T>
struct my_apply {
T* t;
template<typename U>
void operator()(U u) {
u(t);
}
};
template<class C, int T=10, int B=10>
class CountSketch
{
public:
CountSketch()
{
using namespace boost::mpl;
// we need to do this because range_c is not an ExtensibleSequence
typedef typename copy< range_c<int, 0, T>,
back_inserter< vector<> > >::type r;
// fiddle together a vector of the correct types
typedef typename transform<r, typename lambda< assign_hash<C, _1 > >::type >
::type assignees;
// now we need to unfold the type list into a run-time construct
// capture this
my_apply< CountSketch<C, T, B> > apply = { this };
// this is a compile-time loop which actually does something at run-time
for_each<assignees>(apply);
};
// no way around
template<typename TT, typename I>
friend struct assign_hash;
private:
template<int offset>
size_t hash(C& c)
{
return c;
// return (reinterpret_cast<int>(&c)+offset)%B;
}
size_t (CountSketch::*hashfuncs[T])(C &c);
};
// mpl uses int_ so we don't use a non-type template parameter
// but get a compile time value through the value member
template<class C, class I>
struct assign_hash {
template<typename T>
void operator()(T* t) {
t->hashfuncs[I::value] = &CountSketch<C>::template hash<I::value>;
}
};
int main()
{
CountSketch<int> a;
}
with C++20 and consteval compile time loops became possible without doing template hell unless the value can have multiple types:
consteval int func() {
int out = 0;
for(int i = 10; i--;) out += i;
return out;
}
int main() {
std::cout << func(); // outputs 45
}
There are compilers that will see the loop and unroll it. But it's not part of the language specification that it must be done (and, in fact, the language specification throws all sorts of barriers in the way of doing it), and there's no guarantee that it will be done, in a particular case, even on a compiler that "knows how".
There are a few languages that explicitly do this, but they are highly specialized.
(BTW, there's no guarantee that the "unrolled" version of your initializations would be done "at compile time" in a reasonably efficient fashion. But most compilers will, when not compiling to a debug target.)
Here is, I think, a better version of the solution given above.
You can see that we use the compile-time recursive on the function params.
This enables putting all the logic inside your class, and the base case of Init(int_<0>) is very clear - just do nothing :)
Just so you won't fear performance penalty, know that the optimizer will throw away these unused parameters.
As a matter of fact, all these function calls will be inlined anyway. that's the whole point here.
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <iostream>
using namespace std;
template <class C, int N = 10, int B = 10>
class CountSketch {
public:
CountSketch() {
memset(&_hashFunctions, sizeof(_hashFunctions), 0); // for safety
Init(int_<N>());
}
size_t HashAll(C& c)
{
size_t v = 0;
for(const auto& h : _hashFunctions)
{
v += (this->*h)(c); // call through member pointer
}
return v;
}
private:
template<int offset>
size_t hash(C &c)
{
return (reinterpret_cast<size_t>(&c)+offset)%B;
}
size_t (CountSketch::*_hashFunctions[N])(C &c);
private: // implementation detail
// Notice: better approach.
// use parameters for compile-time recursive call.
// you can just override for the base case, as seen for N-1 below
template <int M>
struct int_ {};
template <int M>
void Init(int_<M>) {
Init(int_<M - 1>());
_hashFunctions[M - 1] = &CountSketch<C, N, B>::template hash<M>;
printf("Initializing %dth element\n", M - 1);
}
void Init(int_<0>) {}
};
int main() {
int c;
CountSketch<int, 10> cs;
int i;
cin >> i;
printf("HashAll: %d", cs.HashAll(c));
return 0;
}
Compiler Explorer

compile-time counter for template classes

Imagine that you have a lot of classes with a lot of different template parameters. Every class has a method static void f(). You want to collect all these function pointers in a list L.
A run-time solution would be easy:
typedef void (*p)();
std::vector<p> L;
int reg (p x) { static int i = 0; L.push_back(x); return i++; } // also returns an unique id
template <typename T> struct regt { static int id; };
template <typename T> int regt<T>::id = reg (T::f);
template < typename ... T > struct class1 : regt< class1<T...> > { static void f(); };
template < typename ... T > struct class2 : regt< class2<T...> > { static void f(); };
// etc.
The compiler knows all f()s of all instantiated classes at compile-time. So, theoretically it should be possible to generate such a list (a const std::array<p, S> L with some S) as a compile-time constant list. But how? (C++0x solutions are welcome, too).
Why do I need this?
On an architecture with only 256 kB (for code and data), I need to generate objects for incoming ids of classes. Existing serialization frameworks or the run-time solution above are unnecessarily big. Without templates a compile-time solution would be easy, but I want to keep all the advantages templates offer.
Manually
The simplest thing that you can do is just roll the code manually, I don't think that there is much that can be used to your advantage from the templates, so I will use plain classes, where A, B... stand for particular instantiations of your types. That allows for compile time initialization of the types, at the cost of having to remember to update the lookup table whenever a new type is added to the system:
typedef void (*function_t)();
function_t func[] = {
&A::f,
&B::f,
&C::f
};
I would recommend this, from a maintenance point of view. Automating the system will make the code much harder to understand and maintain in the future.
Macros
The simple most automated one, which will probably generate less code is a macro generation system is just using macros. Since this first approach will use extensive use of macros, I will generate the functions automatically, as you did in the previous question. You can remove that part of code if you have (hopefully) given up the path of full code generation through macros.
To avoid having to retype the names of the types in different contexts you can define a macro with all the data you need for any context, and then use other macros to filter what is to be used (and how) in each particular context:
// This is the actual list of all types, the id and the code that you were
// generating in the other question for the static function:
#define FOREACH_TYPE( macro ) \
macro( A, 0, { std::cout << "A"; } ) \
macro( B, 1, { std::cout << "B"; } ) \
macro( C, 2, { std::cout << "C"; } )
// Now we use that recursive macro to:
// Create an enum and calculate the number of types used
#define ENUM_ITEM( type, id, code ) \
e_##type,
enum AllTypes {
FOREACH_TYPE( ENUM_ITEM )
AllTypes_count
};
#undef ENUM_ITEM
// Now we can create an array of function pointers
typedef void (*function_t)();
function_t func[ AllTypes_count ];
// We can create all classes:
#define CREATE_TYPE( type, the_id, code ) \
struct type {\
static const int id = the_id; \
static void func() code\
};
FOREACH_TYPE( CREATE_TYPE )
#undef CREATE_TYPE
// And create a function that will
#define REGISTER_TYPE( type, id, code ) \
func[ i++ ] = &type::func;
void perform_registration() {
int i = 0;
FOREACH_TYPE( REGISTER_TYPE );
};
#undef REGISTER_TYPE
// And now we can test it
int main() {
perform_registration();
for ( int i = 0; i < AllTypes_count; ++i ) {
func[ i ]();
}
}
This is, on the other hand a maintenance nightmare, quite fragile and hard to debug. Adding new types is trivial, just add a new line to the FOREACH_TYPE macro and you are done... and the best of lucks once something fails...
Templates and metaprogramming
On the other hand, using templates you can get close but you cannot get to the single point of definition for the types. You can automate some of the operations in different ways, but at the very least you will need to define the types themselves and add them to a typelist to get the rest of the functionality.
Simplifying the definition of the actual type_list with C++0x code you can start by defining the types and then creating the type_list. If you want to avoid using C++0x, then take a look at the Loki library, but with C++0x a type list is simple enough:
template <typename ... Args> type_list {}; // generic type list
typedef type_list< A, B, C, D > types; // our concrete list of types A, B, C and D
// this is the only source of duplication:
// types must be defined and added to the
// type_list manually [*]
Now we need to use some metaprogramming to operate on the type list, we can for example count the number of elements in the list:
template <typename List> struct size; // declare
template <typename T, typename ... Args> // general case (recursion)
struct size< type_list<T,Args...> > {
static const int value = 1 + size< type_list<Args...>::value;
};
template <> // stop condition for the recursion
struct size< type_list<> > {
static const int value = 0;
};
Having the size of the type list is a first step in our problem, as it allows us to define an array of functions:
typedef void (*function_t)(); // signature of each function pointer
struct registry {
static const int size = ::size< types >::value;
static const function_t table[ size ];
};
function_t registry::table[ registry::size ]; // define the array of pointers
Now we want to register the static functions from each particular type in that array, and for that we create an auxiliar function (encapsulated as a static function in a type to allow for partial specializations). Note that this concrete part is designed to be run during initialization: it will NOT be compile time, but the cost should be trivial (I would be more worried on the binary size with all the templates):
template <typename T, int N> // declaration
struct register_types_impl;
template <typename T, typename ... Args, int N> // general recursion case
struct register_types_impl< type_list<T,Args...>, N> {
static int apply() {
registry::table[ N ] = &T::f; // register function pointer
return register_types_impl< type_list<Args...>, N+1 >;
}
};
template <int N> // stop condition
struct register_types_impl< type_list<>, int N> {
static int apply() { return N; }
};
// and a nicer interface:
int register_types() {
register_types_impl< types, 0 >();
}
Now we need an id function that maps our types to the function pointer, which in our case is the position of the type in the type list
template <typename T, typename List, int N> // same old, same old... declaration
struct id_impl;
template <typename T, typename U, typename ... Args, int N>
struct id_impl< T, type_list<U, Args...>, N > { // general recursion
static const int value = id_impl< T, type_list<Args...>, N+1 >;
};
template <typename T, typename ... Args, int N> // stop condition 1: type found
struct id_impl< T, type_list<T, Args...>, N> {
static const int value = N;
};
template <typename T, int N> // stop condition 2: type not found
struct id_impl< T, type_list<>, N> {
static const int value = -1;
}
// and a cleaner interface
template <typename T, typename List>
struct id {
static const int value = id_impl<T, List, 0>::value;
};
Now you just need to trigger the registration at runtime, before any other code:
int main() {
register_types(); // this will build the lookup table
}
[*] Well... sort of, you can use a macro trick to reuse the types, as the use of macros is limited, it will not be that hard to maintain/debug.
The compiler knows all f()s of all instantiated classes at compile-time.
There's your mistake. The compiler knows nothing about template instantiations in other compilation units. It should now be pretty obvious why the number of instantiations isn't a constant integral expression that could be used as a template argument (and what if std::array was specialized? Halting Problem ahead!)