Skip to content

Instantly share code, notes, and snippets.

@boki1
Created July 19, 2023 16:27
Show Gist options
  • Save boki1/52a3647d955eaccdb2582b8b2f4dce02 to your computer and use it in GitHub Desktop.
Save boki1/52a3647d955eaccdb2582b8b2f4dce02 to your computer and use it in GitHub Desktop.
Pass a function as an argument.
#include <iostream>
#include <functional>
#include <concepts>
// Problem: Pass a function as an argument
// 1. function pointer (old & C-style)
// Ugly but somewhat nice as it is very simple. See https://cdecl.org
// BTW: https://www.youtube.com/watch?v=6eX9gPithBo
namespace solution1 {
// We want to pass this one to function foo.
char *produce_str(int, double, char *) { return 0; }
void foo(char *(*produce_str_callback)(int, double, char *)) {
printf("produced: %s\n", (*produce_str_callback)(1, 3.14, 0));
}
}
// 2. template with lambda (<C++20)
namespace solution2 {
// If we call with foo(3) will fail to compile: "error: 'fun' cannot be used as a function"
template <typename T>
void foo(T fun) {
fun();
}
// How to pass arguments? Ugly - see perfect forwarding: https://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c/.
template <typename Fun, typename ...Args>
void foo2(Fun fun, Args&& ...args) {
fun(std::forward<Args>(args)...);
}
}
// 3.1 contrained template with lambda (<C++20) with enable if - pretty useless.
// Produces very ugly output when called with foo(3).
namespace solution31 {
template <typename Fun>
typename std::enable_if<std::is_function<std::remove_pointer_t<Fun>>::value>::type
foo(Fun fun) {
fun();
}
}
// 3.2 contrained template with lambda (>=C++20) with concepts - great.
// Produces very nice output when called with foo(3).
namespace solution32 {
template <typename Fun>
requires std::invocable<Fun>
void foo(Fun fun) {
fun();
}
// or
template <std::invocable Fun>
void foo2(Fun fun) {
fun();
}
// or
void foo2(std::invocable auto fun) {
fun();
}
// Remark:
// If you check the link for universal references, then you would know that this `fun` might
// be accepted as `Fun&&` instead of `Fun`.
}
// 4. type erasure and std::function (>=C++11)
// Remark: Advanced. See https://en.cppreference.com/w/cpp/utility/functional/function
// and maybe https://www.youtube.com/watch?v=qn6OqefuH08.
namespace solution4 {
void foo(std::function<void(int, double, char*)> fun) {
fun(3, 3.14, 0);
}
}
int main()
{
// Fails: See the comment there for "explanation".
// solution2::foo(3);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment