Search code examples
c++templatestranslationstd-function

Why doesn't std::function participate in overload resolution?


I know that the following code won't compile.

void baz(int i) { }
void baz() {  }


class Bar
{
    std::function<void()> bazFn;
public:
    Bar(std::function<void()> fun = baz) : bazFn(fun){}

};

int main(int argc, char **argv)
{
    Bar b;
    return 0;
}

Because std::function is said not to consider overload resolution, as I read in this other post.

I do not fully understand the technical limitations that forced this kind of solution.

I read about the phases of translation and templates on cppreference, but I can't think of any reasoning that I couldn't find a counterexample to. Explained to a half-layman (still new to C++), what and during which stage of translation makes the above fail to compile?


Solution

  • This doesn't really have anything to do with "phases of translation". It's purely about the constructors of std::function.

    See, std::function<R(Args)> doesn't require that the given function is exactly of the type R(Args). In particular, it doesn't require that it is given a function pointer. It can take any callable type (member function pointer, some object that has an overload of operator()) so long as it is invokable as if it took Args parameters and returns something convertible to R (or if R is void, it can return anything).

    To do that, the appropriate constructor of std::function must be a template: template<typename F> function(F f);. That is, it can take any function type (subject to the above restrictions).

    The expression baz represents an overload set. If you use that expression to call the overload set, that's fine. If you use that expression as a parameter to a function that takes a specific function pointer, C++ can whittle down the overload set to a single call, thus making it fine.

    However, once a function is a template, and you're using template argument deduction to figure out what that parameter is, C++ no longer has the ability to determine what the correct overload in the overload set is. So you must specify it directly.