I was playing around with this answer to investigate how it handles functions with default parameters. To my surprise, the results are different for free functions and operator()
:
template <typename F>
auto func(F f) -> decltype(f(42))
{
int a = 51;
return f(51);
}
template <typename F>
auto func(F f) -> decltype(f(42, 42))
{
int a = 0;
int b = 10;
return f(a, b);
}
int defaultFree(int a, int b = 0)
{
return a;
}
auto defaultLambda = [](int a, int b = 0)
{
return a;
};
int foo()
{
return func(defaultFree);
//return func(defaultLambda);
}
The func(defaultFree)
version above compiles while both func
templates are available. As expected, it picks the second one because default parameters are not considered part of the function signature. Indeed, removing the second func
template causes a compilation error.
However, func(defaultLambda)
does not compile due to ambiguity: Both func
templates match. Removing either one makes this version compile.
(The same happens if you manually write a struct
with a similar operator()
, of course. Latest gcc
, clang
and MSVC
all agree on it, too.)
What is the reason that the default parameter is considered inside the unevaluated SFINAE context for operator()
but not for the free function?
void f(int a = 0) { ... }
was essentially the same asvoid f(int a) { ... }
plusvoid f() { f(0); }
, but whoa, apparently not! – Gregoriogregorius