I'd like to know if it would be possible to call callbacks in a container with just one instruction, without lambda (it's a kind of exercise).
I tried with std::invoke
. Here is my code:
#include <algorithm>
#include <functional>
#include <iostream>
int main()
{
std::function<void(void)> foo = []() { std::cout << "Foo !"; };
std::function<void(void)> bar = []() { std::cout << "Bar !"; };
const std::vector<std::function<void(void)>> callbacks = { foo, bar };
std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke);
return 0;
}
But I get many errors at compilation:
main.cpp: In function ‘int main()’:
main.cpp:12:22: error: no matching function for call to ‘for_each(std::vector >::const_iterator, std::vector >::const_iterator, )’
12 | std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke);
| ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/11/algorithm:62,
from main.cpp:1:
/usr/include/c++/11/bits/stl_algo.h:3814:5: note: candidate: ‘template _Funct std::for_each(_IIter, _IIter, _Funct)’
3814 | for_each(_InputIterator __first, _InputIterator __last, _Function __f)
| ^~~~~~~~
/usr/include/c++/11/bits/stl_algo.h:3814:5: note: template argument deduction/substitution failed:
main.cpp:12:22: note: couldn’t deduce template parameter ‘_Funct’
12 | std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke);
| ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/11/algorithm:74,
from main.cpp:1:
/usr/include/c++/11/pstl/glue_algorithm_defs.h:42:1: note: candidate: ‘template __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void> std::for_each(_ExecutionPolicy&&, _ForwardIterator, _ForwardIterator, _Function)’
42 | for_each(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Function __f);
| ^~~~~~~~
/usr/include/c++/11/pstl/glue_algorithm_defs.h:42:1: note: template argument deduction/substitution failed:
main.cpp:12:22: note: candidate expects 4 arguments, 3 provided
12 | std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke);
| ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Call Stack
# Function File:Line
Local Variables
Variable Value
Registers
Register Value
Display Expressions
Expression Value
Breakpoints and Watchpoints
# Description
I tried also with the line:
std::for_each(callbacks.cbegin(), callbacks.cend(), std::invoke<void(void)>);
but I still have problems:
In file included from /usr/include/c++/11/algorithm:62,
from main.cpp:1:
/usr/include/c++/11/bits/stl_algo.h: In instantiation of ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<const std::function<void()>*, std::vector<std::function<void()> > >; _Funct = void (*)(void (&&)())]’:
main.cpp:12:15: required from here
/usr/include/c++/11/bits/stl_algo.h:3820:12: error: invalid initialization of reference of type ‘void (&&)()’ from expression of type ‘const std::function’
3820 | __f(*__first);
| ~~~^~~~~~~~~~
It is not possible to do it without a lambda because std::invoke
(like many other functions in std
) does not allow to take its address.
You can see some more info about it here: Can I take the address of a function defined in standard library?.
In case it helps, here's how to do it with a lambda:
For each element in the range (which is a callback function in your case), the lambda will be called with it as an argument.
You can then use std::invoke
to call the callback function element:
#include <algorithm>
#include <functional>
#include <iostream>
int main()
{
std::function<void(void)> foo = []() { std::cout << "Foo !"; };
std::function<void(void)> bar = []() { std::cout << "Bar !"; };
const std::vector<std::function<void(void)>> callbacks = { foo, bar };
std::for_each(callbacks.cbegin(),
callbacks.cend(),
[](std::function<void(void)> cb) { std::invoke(cb); });
}
Output:
Foo !Bar !