Created
July 19, 2023 16:27
-
-
Save boki1/52a3647d955eaccdb2582b8b2f4dce02 to your computer and use it in GitHub Desktop.
Pass a function as an argument.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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