2
#include <functional>

bool f1(int a, int b)
{
    return true;
}

int main()
{
    // This compiles
    std::function<bool()> f2 = std::function<bool()>(std::bind(f1, 1, 2));
    std::function<bool()> f1 = f2;

    // These don't compile
    //std::function<bool()> f1 = std::function<bool()>(std::bind(f1, 1, 2));
    //std::function<bool()> f1 = std::bind(f1, 1, 2);
    //std::function<bool()> f1(std::bind(f1, 1, 2));
}

I was trying to overload f1 by providing a std::function of the same name. However, I ran into this curious situation where an intermediate variable f2 must be used or else it doesn't compile. Why is that the case?

The error messages for the 3 cases are as follows

error: no matching function for call to ‘std::function<bool()>::function(std::_Bind_helper<false, std::function<bool()>&, int, int>::type)’
     std::function<bool()> f1 = std::function<bool()>(std::bind(f1, 1, 2));
error: conversion from ‘std::_Bind_helper<false, std::function<bool()>&, int, int>::type’ {aka ‘std::_Bind<std::function<bool()>(int, int)>’} to non-scalar type ‘std::function<bool()>’ requested
     std::function<bool()> f1 = std::bind(f1, 1, 2);
                                ~~~~~~~~~^~~~~~~~~~
error: no matching function for call to ‘std::function<bool()>::function(std::_Bind_helper<false, std::function<bool()>&, int, int>::type)’
     std::function<bool()> f1(std::bind(f1, 1, 2));
                                                 ^

Edit 1

It appears that even with the first case where it compiles, it does not accomplish overloading as I hoped due to the original bool f1(int a, int b) being no longer accessible. But I would still like to know why the compiler compiles for only some of the above cases.


Edit 2 (after closing)

While it turns out the reason for this behaviour was actually quite silly and has nothing to do with std::function, I'll attempt to add some salvageable value by posting how I accomplished what I wanted to do: by namespacing the original f1 function

namespace
{
bool f1(int a, int b)
{
    printf("blah\n");
    return true;
}
}

int main()
{
    // This works
    //std::function<bool()> f2 = std::function<bool()>(std::bind(f1, 1, 2));
    //std::function<bool()> f1 = f2;

    // These work also
    std::function<bool()> f1 = std::function<bool()>(std::bind(::f1, 1, 2));
    //std::function<bool()> f1 = std::bind(::f1, 1, 2);
    //std::function<bool()> f1(std::bind(::f1, 1, 2));
    //
    
    f1();
    ::f1(1,2);
}
Rufus
  • 5,111
  • 4
  • 28
  • 45
  • If you're after the ability to overload things more non-traditionally, you might find use in the "overload pattern" or whatever you want to call it (we really need a searchable name for this): https://www.cppstories.com/2019/02/2lines3featuresoverload.html/ – chris Aug 11 '21 at 06:54
  • After edits, the question asks for something really different. Please don't do it and ask a new one. – Evg Aug 11 '21 at 06:56
  • @Evg Is it though? The title is still asking why my approach of overloading failed, of which the answer (as well as the duplicate suggestions) are still valid. By adding the motivation (which was originally already in the body of the question), I thought some redeemable value could be had from this duplicate question – Rufus Aug 11 '21 at 07:00
  • There is no overloading here. It the intention was to have such an overloading, asking a different question might give more relevant answers. If the question is just about name hiding, then dupes seem to explain what happens. – Evg Aug 11 '21 at 07:14

1 Answers1

2

Variables enter scope as soon as they're declared. That means that they're in scope for their initializer.

In std::function<bool()> f1 = std::bind(f1, 1, 2);, the f1 on the right-hand side of the = refers to the f1 you declared on the left-hand side.

Note that this is not in any way unique to std::function or anything. int a = a; is perfectly well-formed syntactically (though its behavior is undefined).

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52