Skip to content

Instantly share code, notes, and snippets.

@trevnorris
Last active January 27, 2020 21:36
Show Gist options
  • Save trevnorris/61f83f085aa535bfc3f3e6d076d6f0a9 to your computer and use it in GitHub Desktop.
Save trevnorris/61f83f085aa535bfc3f3e6d076d6f0a9 to your computer and use it in GitHub Desktop.
various c++ code examples demonstrating different techniques
// 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));
}
// 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;
}
// 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();
}
// 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