Skip to content

Instantly share code, notes, and snippets.

@duckie
Last active December 6, 2020 14:07
Show Gist options
  • Save duckie/24d7ea892299335f1916 to your computer and use it in GitHub Desktop.
Save duckie/24d7ea892299335f1916 to your computer and use it in GitHub Desktop.
C++11 - make_function : template resolution of a callable (function, lambda or functor) to the corresponding std::function
#include <functional>
namespace functional {
template <typename Function> struct function_traits;
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
using function = const std::function<ReturnType(Args...)>;
};
// Non-const version, to be used for function objects with a non-const operator()
// a rare thing
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...)> {
using function = std::function<ReturnType(Args...)>;
};
template<typename T>
auto make_function(T const& f) ->
typename std::enable_if<std::is_function<T>::value && !std::is_bind_expression<T>::value, std::function<T>>::type
{ return f; }
template<typename T>
auto make_function(T const& f) ->
typename std::enable_if<!std::is_function<T>::value && !std::is_bind_expression<T>::value, typename function_traits<decltype(&T::operator())>::function>::type
{ return static_cast<typename function_traits<decltype(&T::operator())>::function>(f); }
// This overload is only used to display a clear error message in this case
// A bind expression supports overloads so its impossible to determine
// the corresponding std::function since several are viable
template<typename T>
auto make_function(T const& f) ->
typename std::enable_if<std::is_bind_expression<T>::value, void>::type
{ static_assert(std::is_bind_expression<T>::value && false, "functional::make_function cannot be used with a bind expression."); }
} // namespace functional
// Usage example
#include <iostream>
template<typename Return, typename... Args>
int func(std::function<Return(Args...)> f)
{
return sizeof...(Args);
}
int f2(int a, int b, int c) { return a+b+c; }
struct t3 {
int operator() (int a, int b, int c, int d) { return a+b-c-d; }
};
struct t4 {
int roger() { return 0; }
};
int main() {
using functional::make_function;
t3 test;
t4 test2;
std::cout << func(make_function(f2)) << "\n";
std::cout << func(make_function([](int a, int b) { return a+b; })) << "\n";
std::cout << func(make_function(test)) << "\n";
auto bind_expr = std::bind(&t4::roger, test2);
std::function<int()> test3 = bind_expr;
std::cout << func(make_function(test3)) << "\n";
//std::cout << func(make_function(bind_expr)) << "\n"; // static_assert blocks this
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment