Last active
August 29, 2015 14:15
-
-
Save zakarumych/532a3cb0cb924b42f591 to your computer and use it in GitHub Desktop.
switch by argument type / inspired by Rust match
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 <boost/variant.hpp> | |
| #include "type_match.h" | |
| int main(int argc, char** argv) { | |
| boost::variant<int, const char*> x(42); | |
| x.apply_visitor(match( | |
| [](const char* value) { | |
| printf("%s\n", value); // won't be called cause x is int | |
| }, | |
| [](int value) { | |
| printf("%d\n", value); // will be called with value = 42 | |
| } | |
| )); | |
| x = "qwerty"; | |
| x.apply_visitor(match( | |
| [](const char* value) { | |
| printf("%s\n", value); // will be called with value = "qwerty" | |
| }, | |
| [](...) { | |
| // this is called for any type | |
| // but example won't compile without this block | |
| // match must have at least one function suitable for each variant type | |
| } | |
| )); | |
| } |
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 <type_traits> | |
| #include <boost/preprocessor.hpp> | |
| // Undefine at file end | |
| #define IS_CALLABLE_ONE(N) is_callable<F##N, U>::value | |
| #define AND_IS_NOT_CALLABLE_ONE(z, N, _) && !IS_CALLABLE_ONE(N) | |
| #define AND_IS_NOT_CALLABLE_ALL(N) BOOST_PP_REPEAT(N, AND_IS_NOT_CALLABLE_ONE,_) | |
| #define AND_IS_NOT_CALLABLE_ALL_Z(z, N) BOOST_PP_REPEAT_ ## z(N, AND_IS_NOT_CALLABLE_ONE,_) | |
| #define ENABLE_OVERLOAD(N) typename std::enable_if<(IS_CALLABLE_ONE(N) AND_IS_NOT_CALLABLE_ALL(N))>::type* = 0 | |
| #define ENABLE_OVERLOAD_Z(z, N) typename std::enable_if<(IS_CALLABLE_ONE(N) AND_IS_NOT_CALLABLE_ALL_Z(z, N))>::type* = 0 | |
| #define DECAY_T_F(z, N, _) typedef typename std::decay<T##N>::type F##N; | |
| #define CONSTRUCT_F(z, N, _) BOOST_PP_COMMA_IF(N) f##N(std::forward<T##N>(t##N)) | |
| #define OPERATOR(z, N, _) template<typename U> void operator()(U&& u, ENABLE_OVERLOAD_Z(z, N)) { f##N(std::forward<U>(u)); } | |
| #define LIST_F(z, N, _) F##N f##N; | |
| #define LIST_FARGS(z, N, _) BOOST_PP_COMMA_IF(N) std::forward<T##N>(t##N) | |
| #define DEFINE_TYPE_MATCH_N(z, N, _)\ | |
| template<BOOST_PP_ENUM_PARAMS_Z(z, N, typename T)>\ | |
| class type_match_x##N {\ | |
| public:\ | |
| BOOST_PP_REPEAT_ ## z(N, DECAY_T_F, _);\ | |
| typedef void result_type;\ | |
| type_match_x##N(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, N, T, &&t))\ | |
| : BOOST_PP_REPEAT_ ## z(N, CONSTRUCT_F, _) {}\ | |
| BOOST_PP_REPEAT_ ## z(N, OPERATOR, _)\ | |
| private:\ | |
| BOOST_PP_REPEAT_ ## z(N, LIST_F, _);\ | |
| };\ | |
| template<BOOST_PP_ENUM_PARAMS_Z(z, N, typename T)>\ | |
| type_match_x##N<BOOST_PP_ENUM_PARAMS_Z(z, N, T)>\ | |
| match(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, N, T, &&t)) {\ | |
| return type_match_x##N<BOOST_PP_ENUM_PARAMS_Z(z, N, T)>(BOOST_PP_REPEAT_ ## z(N, LIST_FARGS, _));\ | |
| } | |
| template<typename F, typename A> | |
| struct is_callable { | |
| typedef char yes_t; | |
| struct no_t { yes_t x[2]; }; | |
| template<typename T> | |
| static yes_t test(decltype(std::declval<F>()(std::declval<T>()))*); | |
| template<typename T> | |
| static no_t test(...); | |
| enum { value = sizeof(test<A>(nullptr)) == sizeof(yes_t) }; | |
| }; | |
| BOOST_PP_REPEAT_FROM_TO(1, 20, DEFINE_TYPE_MATCH_N, _); | |
| #undef IS_CALLABLE_ONE | |
| #undef AND_IS_NOT_CALLABLE_ONE | |
| #undef AND_IS_NOT_CALLABLE_ALL | |
| #undef AND_IS_NOT_CALLABLE_ALL_Z | |
| #undef ENABLE_OVERLOAD | |
| #undef ENABLE_OVERLOAD_Z | |
| #undef DECAY_T_F | |
| #undef CONSTRUCT_F | |
| #undef OPERATOR | |
| #undef LIST_F | |
| #undef LIST_FARGS | |
| #undef DEFINE_TYPE_MATCH_N |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can be simplified with variadic templates