Last active
December 6, 2020 14:07
-
-
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
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
#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