Why overloaded function cannot be assigned to function type object
-
int add(int i, int j) { return i + j; } std::string add(const std::string & h1, const std::string & h2) { return std::string(); } ...... std::function<int(int, int)> f = add;
The last line reports an error "cannot convert from 'overloaded-function' to 'std::function<int (int,int)>". The template argument of
function
clearly specified the call signature asint(int,int)
, so I think it should select the add function in line 1. I don't understand why the compiler gets confused which overloaded function is the best match.
-
Try
std::function<int(int, int)> f = static_cast<int(*)(int, int)> (add);
Your version does not work, because the constructor of
std::function
is a template itself, accepting practically anything. Thus, the compiler cannot figure out from the template parameters tostd::function
, which way you want to call the constructor, because the constructor argument is unrelated to the class template parameters.The above answer is a summary of the answers to a Stackoverflow question that sounds suspiscously like the question you asked, down to almost literally the same exact code example. Your next post better show you are a human and not some bot trained on stackoverlow questions.
-
@SeppJ Based on your answer, if I comment out line 1, the code should work because 1) it forcibly cast call signature (your answer) and 2) there is onlyy one
add
function left (no overload any more). But the compiler complains with a similar error. How to explain that?I have no idea what was happening in Stackoverflow and I am a human with straight gender. Copying answer from other place without really understanding what is asked looks more like a bot.
-
@zzzhhh sagte in Why overloaded function cannot be assigned to function type object:
@SeppJ Based on your answer, if I comment out line 1, the code should work because 1) it forcibly cast call signature (your answer) and 2) there is onlyy one
add
function left (no overload any more). But the compiler complains with a similar error. How to explain that?The first line is the one you want, is it not? It is the second function that is interferring. If you remove the second line, the code will work without the cast.
Removing the first line will obviously not work, because the remaining
string(const string&, const string&)
is not compatible toint(int, int)
.
-
@SeppJ I was not asking how to fix the code so that there is no error; the textbook I read gives me two methods of fixing it. What I am asking is I don't understand why the second
add
function can confuse the compiler even if tthis overloaded version is incompatible with the needed call signature. Since it is incompatible, why didn't the compiler just skips it and go ahead to the best match (line 1) but utters an error?
-
As I said: It is the
std::function
constructor. Look at the reference:
https://en.cppreference.com/w/cpp/utility/functional/function/functionThe class
std::function<R(Args...)>
has (among many others) the constructortemplate< class F > function( F&& f )
. That template parameterF
is completely unrelated to the template parameters of the function. It could be anything. Therefore, the compiler has no hint as to whichadd
you could mean, because both fit a genericF&&
. Hence, just writingadd
is ambiguous in this context, you must specify which one you mean.That ambiguity must be resolved before the compiler can instantiate the constructor template, after all, it must know what
F&&
is. If you resolve the ambiguity by removing the first line, the constructor gets instantiated withF
asstring(string const&, string const&)
and then the compiler can see inside that constructor that the combination ofint(int, int)
andstring(string const&, string const&)
does not work and raises a different (though similar sounding) error.The rules of the language say, that ambiguity is an error. The compiler should not try all possible interpretations of your code and decide that one of them leads to fewer errors down the line, and is therefore correct. Well, it kind of should do this when SFINAE is involved, but there it is a one step process, where the incompatible choices would lead to immediate errors. With the
std::function
constructor, though, the actual error would happen at some later point. That is something the compiler cannot know while deciding whichadd
is meant, because it is not allowed to look into the future.
-
Consider this code:
int add(int i, int j) { return i + j; } std::string add(const std::string & h1, const std::string & h2) { return std::string(); } template <typename T> class MyFunction { T &t; public: MyFunction(T && t): t(t) {}; }; int main() { MyFunction<int(int, int)> mf = add; }
This works perfectly fine. The
T
constructor parameter is the same as the class template parameter. Hence the compiler knows in line 12 that something compatible toint(int, int)
is required. That leaves only one possible choice ofadd
and the code works fine.You might ask "Why is
std::function
not implemented that way? Even SeppJ could figure out something better!". The answer is, that I did not figure out something better.MyFunction
is a pale comparison tostd::function
. My example is only a function pointer with extra steps, whereasstd::function
has a much wider range of options as to what exactly its callable is. The code for that has to happen somewhere, and unfortunately it cannot be done before the constructor call is even resolved.
-
Dieser Beitrag wurde gelöscht!
-
OK, I think I figure out the key. When matching overloaded functions, we have a single concrete argument and find the best match according to the type of the given argument, in this orderr. But I confused by reversing this order. The situation in my question is that I have two arguments of different types with the same name, but only one constructor function. So function matching (overload resolution) does not apply at all. The compiler did not know that thus got confused.
In short, roughly speaking, function matching is 1 argument -> 2 functions. But my question is 2 arguments -> 1 function. Not applicable.
-
I am not sure you mean the right thing. But it is correct, that overload resolution does not apply here, and that is indeed why the compiler cannot know what exactly you mean when you refer to
add
. There is just nothing to go on here to give it a hint.I do not know what you mean with your numbers. It's just plain old ambiguity. It does not matter if there are 2, 3, or 2000 candidates.
-
Guten Morgen,
das Problem entsteht durch die Überladung der Funktion
add
.Zusammenfassung des Problems
Du hast zwei überladene Funktionen:
int add(int i, int j) { return i + j; } std::string add(const std::string& h1, const std::string& h2) { return std::string(); }
Und Du versuchst, eine dieser Funktionen einer
std::function
zuzuweisen:std::function<int(int, int)> f = add;
Hier entsteht der Fehler:
"cannot convert from 'overloaded-function' to 'std::function<int (int,int)>"
.Erklärung des Fehlers
Der Compiler kann nicht bestimmen, welche der überladenen Funktionen
add
verwendet werden soll, weilstd::function
ein Template-Konstruktor ist, der praktisch alles akzeptiert. Ohne weitere Hinweise vom Benutzer kann der Compiler nicht entscheiden, welcheadd
-Funktion zuzuweisen ist, weil beide überladenen Varianten zum generischen TemplateF&&
passen.Lösung
Um dies zu lösen, musst du den Funktionszeiger explizit in den gewünschten Typ konvertieren:
std::function<int(int, int)> f = static_cast<int(*)(int, int)>(add);
Durch diesen Cast wird die richtige Überladung ausgewählt.