variadic function template without formal parameters

Another way is turning the non-template function f into a variadic template function which accepts zero or more template arguments (the other f requires one or more template arguments). Then to avoid ambiguity, SFINAE away this template function when the number of arguments is not zero. Well, a code is better than 1000 words:

#include <type_traits>

template <typename... Ts>
typename std::enable_if<sizeof...(Ts) == 0>::type f() {
}

template <typename T, typename... Ts>
void f() {
    // do something with T
    f<Ts...>();
}

Since class templates can be partially specialized, another possibility is to use class templates to do the work, and have your function delegate to them:

template<typename... Ts>
struct caller
{
    static void call() { } // Base case, terminates recursion
};

template<typename T, typename... Ts>
struct caller<T, Ts...>
{
    static void call()
    {
        // Do something with T
        caller<Ts...>::call();
    }
};

template<typename... Ts>
void f() {
    caller<Ts...>::call();
}