barney barney - 2 months ago 6x
C++ Question

how to declare properly the template taking function type as a parameter (like a std::function)

I found out that its not trivial to have a neat syntax like in:

std::function<int(float, bool)>

If I declare the function as:

template <class RetType, class... Args>
class function {};

It would be an ordinary syntax to define function's templated types:

function<int,float,bool> f;

But it works with strange trick with partial template specialization

template <class> class function; // #1

template <class RV, class... Args>
class function<RV(Args...)> {} // #2

Why is that?
Why I need to give the template an empty general form with empty type parameter (#1) or otherwise it just won't compile


This is just the way the language was designed. Primary templates can't do complex decomposition of types like that; you need to use partial specialization.

If I understand correctly, you would like to just write the second version without having to supply the primary template. But think about how the template arguments map to the template parameters:

template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}

function<int(float,bool)>; //1
function<int, float, bool>; //2

Option 1 is what you want to write, but note that you pass a single function type to a template where the parameters are a two type parameters and a type parameter pack. In other words, writing this without a primary template means that your template arguments wouldn't necessarily match the template parameters. Option 2 matches the template parameters, but it doesn't match the specialization.

This makes even less sense if you have more than one specialization:

template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}

template <class T, class RV, class Arg1, class... Args>
class function<RV (T::*) (Arg1, Args...)> {}

You could maybe think up some rules to infer the primary template from the specializations, but that seems pretty awful to me.