Created
March 24, 2023 02:57
-
-
Save zeroxia/902017ee03e60ef52e076bceefc4591e to your computer and use it in GitHub Desktop.
Wrap a callable object according to its functional signature, and return a corresponding std::function<void()>.
This file contains hidden or 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 <type_traits> | |
#include <iostream> | |
#include <functional> | |
/* | |
* Type dispatching example. | |
* Stolen from: https://stackoverflow.com/questions/87372/check-if-a-class-has-a-member-function-of-a-given-signature | |
* Live demo: | |
* https://godbolt.org/z/1cxjG4Th9 | |
*/ | |
namespace t1 { | |
// Primary template with a static assertion for a meaningful error message if it ever gets instantiated. | |
template<typename Type, typename Signature> | |
struct IsFunctor { | |
static_assert( | |
std::integral_constant<Signature, false>::value, | |
"Second template parameter needs to be of function type."); | |
}; | |
// Specialization that does the checking. | |
template <typename C, typename Ret, typename... Args> | |
struct IsFunctor<C, Ret(Args...)> { | |
private: | |
template <typename T> | |
static constexpr auto check(int) | |
-> typename | |
std::is_same< | |
decltype( std::declval<T>()(std::declval<Args>()... ) ), | |
Ret | |
>::type; | |
template<typename> | |
static constexpr std::false_type check(...); | |
using type = decltype(check<C>(0)); | |
public: | |
static constexpr bool value = type::value; | |
}; | |
struct TypeA { | |
int operator()(int, double) { return 1; } | |
}; | |
struct TypeB { | |
float operator()(int, double) { return -3.14F; } | |
}; | |
struct Dispatcher { | |
template <typename T> | |
static | |
std::enable_if_t< | |
IsFunctor<std::remove_reference_t<T>, int(int, double)>::value, | |
std::function<void()> | |
> | |
wrap(T&& t) { | |
return [callable = std::move(t)] () mutable { | |
auto ret = callable(3, 3.14); | |
std::cout << "wrapped int(int, double): ret = " << ret << std::endl; | |
}; | |
} | |
template <typename T> | |
static | |
std::enable_if_t< | |
IsFunctor<std::remove_reference_t<T>, float(int, double)>::value, | |
std::function<void()> | |
> | |
wrap(T&& t) { | |
return [callable = std::move(t)] () mutable { | |
auto ret = callable(3, 3.14); | |
std::cout << "wrapped float(int, double): ret = " << ret << std::endl; | |
}; | |
} | |
}; | |
int FunC(int a, double b) { | |
return static_cast<int>(a * b); | |
} | |
void test() { | |
std::cout << "check TypeA:\n"; | |
auto f = Dispatcher::wrap(TypeA{}); | |
f(); | |
TypeA A; | |
f = Dispatcher::wrap(A); | |
f(); | |
std::cout << "check TypeB:\n"; | |
f = Dispatcher::wrap(TypeB{}); | |
f(); | |
TypeB B; | |
f = Dispatcher::wrap(B); | |
f(); | |
std::cout << "check FunC:\n"; | |
f = Dispatcher::wrap(&FunC); | |
f(); | |
f = Dispatcher::wrap(FunC); | |
f(); | |
} | |
} // namespace t1 | |
int main() { | |
t1::test(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The code requires C++14, but can be changed to support C++11 as follows:
std::enable_if_t
, usetypename std::enable_if<...>::type
std::remove_reference_t
, usetypename std::remove_reference<...>::type
https://godbolt.org/z/G4a4osYvM
Revised C++14 version using
std::forward<T>
instead ofstd::move
:https://godbolt.org/z/7xWPT8T87