Formally, lambda expressions can be used as default arguments. However, the default arguments will not be taken into account in the deduction process of the template arguments. This means that, in fact, the BinaryFunc type BinaryFunc not be deduced even with the successfully deduced type T That is, the "natural" syntax of a function call will not work.
int a = 5, b = 10; testFunc(a, b); // Ошибка - невозможно дедуцировать тип `BinaryFunc`
You cannot specify the exact type of this argument explicitly manually, because the type of lambda expression is unknown to you. You can specify std::function<int(int, int)> as the type of BinaryFunc and it will work
int a = 5, b = 10; testFunc<int, std::function<int(int, int)>>(a, b);
but in such a situation, the need for an independent template parameterization for this parameter generally disappears. Those. you can just do it
template<class T> T testFunc(T t1, T t2, std::function<T(T, T)> func = [](T v1, T v2){return v1 < v2;}) { return func(t1, t2); }
and forget about the need to deduce the type of this argument. (In fact, the main purpose of std::function is precisely how to get rid of the template code parametrization. The price for this is the potential internal inefficiency of std::function .)
Your original functionality can be "emulated" by overloading the function instead of using the default argument.
template<class T, class BinaryFunc> T testFunc(T t1, T t2, BinaryFunc func) { return func(t1, t2); } template<class T> T testFunc(T t1, T t2) { return testFunc(t1, t2, [](T v1, T v2){return v1 < v2;}); }