In general you define a simple template class like this:
template<typename T>
class A
{
};
This can then be used with
A<int> myA;
Sometimes you want to have a different implementation for a specific type which we call a template specialization:
template<>
class A<int>
{
};
Just as with function overloading where the compiler picks the function with the best fit for the parameter types, the compiler will pick the most specific specialization.
Sometimes you don't want a specific type but some specific sort of type, e.g. a pointer:
template<typename T>
class A<T*>
{
};
Now, if you write A<int*> pInt; or A<double*> pDouble; it will match the specialization for pointers. In the same way class Logger3<R(Args...)> will match any function as template argument. One of the "modern C++" features is Args... which means any number of types (0 or more). (The ... introduces a list of types.) So, R(Args...) can match void() or void(int) or int(double,int) etc. Because we are just interested in the function signature this looks like a function declaration, but without any function name between the return type and the argument list.