Last active
January 27, 2020 21:36
-
-
Save trevnorris/61f83f085aa535bfc3f3e6d076d6f0a9 to your computer and use it in GitHub Desktop.
various c++ code examples demonstrating different techniques
This file contains 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
// Demonstrates how to pass a template function to a non-template function | |
// pointer by specifying the template parameter when it's assigned. | |
// This allows the void* to be safely cast when the function is called. | |
#include <cstdio> | |
struct A { int val = 42; }; | |
struct B { int foo = 0; int val = 45; }; | |
void (*cbp)(void*); | |
template <typename T> | |
void f1(void* a) { | |
printf("f1 t->val: %d\n", static_cast<T*>(a)->val); | |
} | |
template <typename T> | |
void f2(T*) { | |
cbp = &f1<T>; | |
} | |
template <typename T> | |
void f3(void* a) { | |
printf("f3 t->val: %d\n", static_cast<T*>(a)->val); | |
} | |
template <typename T> | |
void f4(T*) { | |
cbp = &f3<T>; | |
} | |
int main() { | |
A* a = new A(); | |
f2(a); | |
cbp(static_cast<void*>(a)); | |
B* b = new B(); | |
f4(b); | |
cbp(static_cast<void*>(b)); | |
} |
This file contains 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
// Demonstrates the same template function pointer technique using a libuv API | |
#include <uv.h> | |
struct A { | |
int val = 42; | |
}; | |
template <typename T> | |
void thread_routine(void* arg) { | |
printf("t->val: %d\n", static_cast<T*>(arg)->val); | |
} | |
int main() { | |
uv_thread_t thread; | |
A* a = new A(); | |
uv_thread_create(&thread, &thread_routine<A>, a); | |
uv_thread_join(&thread); | |
delete a; | |
} |
This file contains 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
// Shows how to use perfect forwarding to bind and run a function in the future. | |
#include <cstdio> | |
#include <functional> | |
#include <memory> | |
class A { | |
public: | |
template <typename F, typename... Args> | |
void SetCb(F&& cb, Args&&... args) { | |
// Here's the important bits. | |
typedef decltype(std::bind(std::forward<F>(cb), | |
std::forward<Args>(args)...)) CB_td; | |
arg_ptr_ = new CB_td(std::bind(std::forward<F>(cb), | |
std::forward<Args>(args)...)); | |
cb_ptr_ = &cb_proxy<CB_td>; | |
} | |
void RunOnce() { | |
cb_ptr_(arg_ptr_); | |
} | |
template <typename T> | |
static void cb_proxy(void* arg) { | |
auto* cb = static_cast<T*>(arg); | |
(*cb)(); | |
delete cb; | |
} | |
private: | |
void* arg_ptr_ = nullptr; | |
void (*cb_ptr_)(void*); | |
}; | |
void fn1(int a, int b) { | |
printf("fn1: %d %d\n", a, b); | |
} | |
void fn2(A* ptr) { | |
printf("fn2: %p\n", ptr); | |
} | |
int main() { | |
std::unique_ptr<A> a(new A()); | |
a->SetCb(fn1, 42, 45); | |
a->RunOnce(); | |
a->SetCb(fn2, a.get()); | |
a->RunOnce(); | |
} |
This file contains 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
// Runs a bound function in the future, but also using a placeholder so | |
// the user can pass in an argument that'll arrive. | |
#include <functional> | |
#include <cstdio> | |
struct S { | |
~S() { | |
cleanup_cb_(data_ptr_); | |
} | |
template <typename CB, typename... Args> | |
void fn(CB&& cb, Args&&... args) { | |
typedef decltype(std::bind(std::forward<CB>(cb), | |
std::placeholders::_1, | |
std::forward<Args>(args)...)) G_t; | |
auto* g = new G_t(std::bind(std::forward<CB>(cb), | |
std::placeholders::_1, | |
std::forward<Args>(args)...)); | |
data_ptr_ = g; | |
run_cb_ = call_data_ptr_<G_t>; | |
cleanup_cb_ = cleanup_<G_t>; | |
} | |
void run(int v) { | |
run_cb_(data_ptr_, v); | |
} | |
template <typename G> | |
static void call_data_ptr_(void* g, int v) { | |
(*static_cast<G*>(g))(v); | |
} | |
template <typename G> | |
static void cleanup_(void* g) { | |
delete static_cast<G*>(g); | |
} | |
void* data_ptr_; | |
void (*run_cb_)(void*, int); | |
void (*cleanup_cb_)(void*); | |
}; | |
void testfn(int v, S* s1, S* s2) { | |
printf("%d\n", v); | |
} | |
int main() { | |
S s; | |
s.fn(testfn, &s, &s); | |
s.run(43); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment