0

I have a function wrapper that takes a function and a list of arguments and calls the function with those arguments:

template<typename R, typename... Args>
R wrapper(std::function<R(Args...)> f, Args... args) {
    auto ret = f(args...);
    return ret;
}  

But the following does nott compile:

int f1(int a, int b) { return a+b; }

wrapper(f1, 1, 2);

It says:

mismatched types ‘std::function<_Res(_ArgTypes ...)>’ and ‘int (*)(int, int)’

However, if I do:

wrapper(std::function<int(int, int)>(f1), 5, 10);

...it will be well-formed, which is contradictory with the compiler error.

Why doesn't the compiler accept the first version?

Demo trace: https://onlinegdb.com/rJWzZIQX4

Holt
  • 36,600
  • 7
  • 92
  • 139
zeralight
  • 620
  • 1
  • 5
  • 19
  • There is no contradiction here. The compiler's telling you that `std::function<_Res(_ArgTypes ...)>` is not the same type as `int (*)(int, int)` (and that it's not allowed to implicitly convert the latter to the former). In your second example, you explicitly convert it so the compiler is happy. – JMAA Jan 21 '19 at 14:16
  • 1
    FWIW, in C++17 `std::function(f1)` can be shortened to `std::function{f1}` to save you some typing and repeating. – NathanOliver Jan 21 '19 at 14:17
  • @StoryTeller Hm, that doesn't work for me: `candidate template ignored: could not match 'function' against 'int (*)(int, int)'` – lubgr Jan 21 '19 at 14:22
  • Also highly related and also tells you why lambdas also have this issue: https://stackoverflow.com/questions/9998402/c11-does-not-deduce-type-when-stdfunction-or-lambda-functions-are-involved – NathanOliver Jan 21 '19 at 14:23
  • @lubgr - Interesting. I would have thought that with the types deduced/specified this should be enough. Oh well. – StoryTeller - Unslander Monica Jan 21 '19 at 14:24

1 Answers1

1

When deducing template parameters, the compiler does not perform any conversions. Hence, in

wrapper(f1, 1, 2);

you are requesting the implicit construction of std::function<int(int, int)> from a function pointer of type int (*)(int, int). When explicitly passing std::function<int(int, int>(f1), there is no need for converting the argument, and the argument deduction works out.

lubgr
  • 37,368
  • 3
  • 66
  • 117