One particulary interesting CRTP case

Consider the following task. We have some class X, parametrized by method (say you will use this method as callback). Everything looks simple:

void bar (int *x);
template <void (*pfoo)(int*)> 
struct X {
void call(int *py) { pfoo(py); }
};
int s = 42;
X<bar> t;
t.call(&s); //ok

Now lets complicate the task. Consider we have template function and want X to be parametrized by its particular instance. Still no problems

template <typename T>
void bar (T *x);
template <typename U, void (*pfoo)(U*)> 
struct X {
void call(U *py) { pfoo(py); }
};
int s = 42;
X<int, bar<int>> t;
t.call(&s); //ok

But now lets make things tricky: what about parametrizing X with function bar, parametrized with X itself?

Something like:

X<X, bar<X>> t; // Fail
t.call(&t); // <-- we want this

This is not legal, because X itself shall be specified with parameter, etc…

Solution comes trough CRTP:

template <typename T>
void bar (T *x);
template <typename U, void (*pfoo)(U *pt)>
struct Xbase {
void call(U *pt) { pfoo(pt); }
};
struct X: Xbase<X, bar<X>> {
void call(X *pt) { Xbase::call(pt); }
};
X t; // t implicitly parametrized by bar<X>
t.call(&t); //ok

But what if we want to explicitly select bar in point of parametrization, like this:

X<bar> t;
t.call(&t); //ok, called bar<X>

Then we got stuck. No template template non-type parameters in standard. So sad.

Like what you read? Give Konstantin Vladimirov a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.