It can use partial template specialization. Look at this:
template <typename T>
class Func;
template <typename R, typename... Args>
class Func<R(Args...)>
{
public:
Func(R(*fptr)(Args...)) {/*do something with fptr*/}
};
This class takes a single template parameter. But unless it matches R(Args...)
(i.e. a function type returning R and taking zero or more args), there wont be a definition for the class.
int main() { Func<int> f; }
// error: aggregate 'Func<int> f' has incomplete type and cannot be defined
.
int func(double a) { return a+2; }
int main() { Func<int(double)> f = func; }
// ok
The specialization can now operate on R
and Args
to do its magic.
Note that int(double)
is a function type. Since you cannot create raw function objects, you don't usually see this syntax outside the template world. If T
is int(double)
then T*
is a function pointer just like int(*)(double)
.