Last active
November 21, 2019 00:28
-
-
Save talybin/d61e87cb020fee20b5a3ca43e7b9f53e to your computer and use it in GitHub Desktop.
An attempt to any function holder type with only requirement to simillar return type. Has a lot of issues. Do not use!
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
| #pragma once | |
| #include <functional> | |
| #include <any> | |
| template <class T> | |
| struct fn_signature | |
| : fn_signature<decltype(std::function(std::declval<T>()))> | |
| { }; | |
| template <class T> | |
| struct fn_signature<std::function<T>> : fn_signature<T> | |
| { }; | |
| template <class R, class... Args> | |
| struct fn_signature<R(Args...)> | |
| { | |
| using return_type = R; | |
| using type = R(Args...); | |
| template <class T> | |
| using set_rtype = T(Args...); | |
| }; | |
| // Any value auto cast | |
| struct any_value : std::any | |
| { | |
| using std::any::any; | |
| template <class T> | |
| operator T() { | |
| return std::any_cast<T>(*this); | |
| } | |
| }; | |
| // std::any or void will accept any function | |
| template <class R = any_value> | |
| struct any_function | |
| { | |
| any_function() = default; | |
| template <class F> | |
| any_function(F&& fn) | |
| { | |
| using fn_sign = fn_signature<F>; | |
| using cast_sign = typename fn_sign::template set_rtype<R>; | |
| fn_ = std::function<cast_sign>([fn = std::forward<F>(fn)](auto&&... args) -> R | |
| { | |
| if constexpr (std::is_same_v<R, void>) | |
| fn(std::forward<decltype(args)>(args)...); | |
| else if constexpr (std::is_same_v<typename fn_sign::return_type, void>) { | |
| fn(std::forward<decltype(args)>(args)...); | |
| return { }; | |
| } | |
| else | |
| return fn(std::forward<decltype(args)>(args)...); | |
| }); | |
| } | |
| template <class... Args> | |
| R operator()(Args&&... args) const | |
| { | |
| using fn_type = std::function<R(Args...)>; | |
| if (auto fn = std::any_cast<fn_type>(&fn_)) | |
| return (*fn)(std::forward<Args>(args)...); | |
| else | |
| throw std::bad_function_call(); | |
| } | |
| private: | |
| std::any fn_; | |
| }; |
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
| // Any function holder type with only requirement to simillar return type | |
| #pragma once | |
| #include <functional> | |
| #include <any> | |
| template <class T> | |
| struct fn_signature | |
| : fn_signature<decltype(std::function(std::declval<T>()))> | |
| { }; | |
| template <class T> | |
| struct fn_signature<std::function<T>> : fn_signature<T> | |
| { }; | |
| template <class R, class... Args> | |
| struct fn_signature<R(Args...)> | |
| { | |
| using return_type = R; | |
| using type = R(Args...); | |
| template <class T> | |
| using set_rtype = T(Args...); | |
| }; | |
| // void will accept any function | |
| template <class R = void> | |
| struct ret_function | |
| { | |
| ret_function() = default; | |
| template <class F> | |
| ret_function(F&& fn) | |
| { | |
| using fn_sign = fn_signature<F>; | |
| using cast_sign = typename fn_sign::template set_rtype<R>; | |
| static_assert(std::is_same_v<R, void> || // Skip check if R is void | |
| std::is_convertible_v<typename fn_sign::return_type, R>); | |
| fn_ = std::function<cast_sign>(std::forward<F>(fn)); | |
| } | |
| template <class... Args> | |
| R operator()(Args&&... args) const | |
| { | |
| using fn_type = std::function<R(Args...)>; | |
| if (auto fn = std::any_cast<fn_type>(&fn_)) | |
| return (*fn)(std::forward<Args>(args)...); | |
| else | |
| throw std::bad_function_call(); | |
| } | |
| private: | |
| std::any fn_; | |
| }; |
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 "ret_function.hpp" | |
| #include <iostream> | |
| int main() | |
| { | |
| int a = 100; | |
| auto b = [&](int x) { | |
| return "sum: " + std::to_string(x + a); | |
| }; | |
| ret_function<std::string> fn(b); | |
| std::cout << fn(42) << '\n'; | |
| try { | |
| fn(1, 2, 3); | |
| throw std::runtime_error("not expected"); | |
| } | |
| catch (const std::bad_function_call&) { | |
| std::cout << "throw expected\n"; | |
| } | |
| fn = [](int a, int b, int c) { | |
| #if 0 | |
| // Compile time error: return type do not match | |
| return 4; | |
| #else | |
| // OK: char array is convertible to std::string | |
| return "4"; | |
| #endif | |
| }; | |
| std::cout << fn(1, 2, 3) << '\n'; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output: