1

The following code won't build, any feedback on the cause would be appreciated.

void bar(std::string str, int& a, int& b) { } template<typename T, typename ... Args> void foo(std::function<void(T, Args...)> fcn, Args ... args) { // Some code that calls fcn } void run() { int a = 3; int b = 5; foo<std::string, int&, int&>(bar, a, b); } 

It is a modified implementation of the first solution proposed in this SO answer.

The IDE gives the following error on the line calling foo:

C++ template<class T, class... Args> void foo(std::function<void (T, Args...)> fcn, Args ...args)

no instance of function template "foo" matches the argument list
argument types are:
(void (std::string str, int &a, int &b), int, int)

Tested separately, it seems like passing a fcn argument with template arguments are fine. The issue seems to be with passing a function argument where the function can accept variadic template arguments.

3 Answers 3

3

Function (pointer) is not a std::function, so doesn't work for deduction.

You might make Ts... non deducible in that context

template<typename T, typename ... Args> void foo(std::function<void(T, std::type_identity_t<Args>...)> fcn, Args ... args) { // Some code that calls fcn } 

Demo

or drop std::function completely

template<typename T, typename F, typename ... Args> requires (std::is_invocable<F, T, Args...>::value) void foo(F fcn, Args&& ... args) { // Some code that calls fcn } 

Demo

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks! Is there a workaround that doesn't require c++20? It seems type_identity was added with c++20.
The same is true for std::is_invocable. Both answers are appreciated, regardless.
But deduction isn't happening if the template arguments are specified.
std::type_identity can be re-implemented easily.
requires usage can be replaced by auto foo(F f, Args&&... args) -> decltype(f(std::declval<T>(), std::forward<Ts>(args)...), void())
|
1
  • & when I removed it, there was no error
#include <iostream> #include <functional> void bar(std::string str, int a, int b) { } template<typename T, typename ... Args> void foo(std::function<void(T, Args...)> fcn, Args ... args) { // Some code that calls fcn } int main() { std::function<void(std::string, int, int)> func_1 = bar; int a = 3; int b = 5; foo(func_1, a, b); return 0; } 
  • If it is necessary to use Call by Reference, I tried it by giving a direct address and it worked in this case too.
#include <iostream> #include <functional> void bar(std::string str, int* a, int* b) { } template<typename T, typename ... Args> void foo(std::function<void(T, Args...)> fcn, Args ... args) { // Some code that calls fcn } int main() { std::function<void(std::string, int*, int*)> func_1 = bar; int a = 3; int b = 5; foo(func_1, &a, &b); return 0; } 

1 Comment

Great, thanks. The func_1 line helps a lot.
1

Thanks all. Going off of the answer by serkan the following seems to work.

#include <iostream> #include <functional> void bar(std::string str, int& a, int& b) { } template<typename T, typename ... Args> void foo(std::function<void(T, Args...)> fcn, Args ... args) { // Some code that calls fcn } int main() { std::function<void(std::string, std::reference_wrapper<int>, std::reference_wrapper<int>)> func_1 = bar; int a = 3; int b = 5; foo(func_1, std::ref(a), std::ref(b)); foo((std::function<void(std::string, std::reference_wrapper<int>, std::reference_wrapper<int>)>)bar, std::ref(a), std::ref(b)); return 0; } 

I'll run more tests, there might still be some changes needed.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.