Last active
December 14, 2015 00:59
-
-
Save cbsmith/5002638 to your computer and use it in GitHub Desktop.
Me proving myself wrong.
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
// -*- compile-command: "clang++ -std=c++11 -stdlib=libc++ -Wall -Werror func.cc -o func" -*- | |
#include <iostream> | |
#include <functional> | |
#include <utility> | |
#include <iomanip> | |
//The ugly beast we're wrapping | |
template <typename T1, typename T2, typename T3> | |
struct Hooks3 { | |
virtual bool Fire (int *, T1 t1, T2 t2, T3 t3) { return false; } | |
}; | |
//More generic version of a hook wrapper... Who creates classes called Hook2, Hook3...? ;-) | |
template <template <typename...> class H, typename... Ts> | |
struct LambdaHook : public H<Ts...> { | |
typedef H<Ts...> hook_t; | |
typedef std::function<bool(Ts...)> func_t; | |
//Since we are doing return type polymorphism, we can afford for this to be | |
//explicit | |
inline explicit LambdaHook(func_t&& a_func) | |
: hook_t(), func(std::move(a_func)) {} | |
bool Fire(int* ignored, Ts... args) override { | |
if (nullptr != ignored) | |
std::cout << "Ignoring " << (*ignored) << std::endl; | |
else | |
std::cout << "Ignoring a null pointer" << std::endl; | |
return func(std::forward<Ts>(args)...); | |
} | |
private: | |
func_t func; | |
}; | |
template <typename F> | |
struct return_type_polymorphism_magic { | |
typedef F raw_func_t; | |
inline return_type_polymorphism_magic(raw_func_t&& a_func) | |
: f(std::move(a_func)) {} | |
template <template <typename...> class H, typename... Args> | |
inline operator H<Args...>*()&& { | |
typedef LambdaHook<H, Args...> lambda_t; | |
//this whole instance is meant to be single use, so pass f with move semantics. | |
return new lambda_t(typename lambda_t::func_t(std::move(f))); | |
} | |
private: | |
//keep this away from prying eyes | |
raw_func_t f; | |
}; | |
//Make's a hook out of any function... even a lambda... even a lambda whose closure isn't void. | |
// | |
//Okay, actually it doesn't. It really just copies the object in to a class designed to detect the | |
//return type by way of conversion operation, and THAT class does all the work | |
template <typename P> | |
inline auto make_hook(P p) -> decltype( return_type_polymorphism_magic<P>(std::forward<P>(p)) ) { | |
return return_type_polymorphism_magic<P>(std::forward<P>(p)); | |
} | |
int main (int argc, char **argv) | |
{ | |
std::string foobar = "Help, I've been captured by a closure!"; | |
Hooks3<int, int, int>* hook = | |
make_hook([foobar](int a, int b, int c) -> bool { | |
std::cout << "a: " << a << std::endl | |
<< "b: " << b << std::endl | |
<< "c: " << c << std::endl | |
<< "foobar: " << foobar << std::endl; | |
return true; | |
}); | |
int ignored = 42; | |
bool fired = hook -> Fire (&ignored, 3, 5, 8); | |
std::cout << "fired: " << std::boolalpha << fired << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment