diff options
author | Murray Cumming <murrayc@murrayc.com> | 2016-03-02 10:46:18 +0100 |
---|---|---|
committer | Murray Cumming <murrayc@murrayc.com> | 2016-03-02 11:52:29 +0100 |
commit | 8fac95524c7cbf70c388f72c5aa0717a8a5e4859 (patch) | |
tree | dd84d0e943cc7cd3e3683eab26ce945313603f25 | |
parent | f6202b9e7ed9b92efbc683eb804f6ec559c32a9a (diff) | |
download | sigc++-8fac95524c7cbf70c388f72c5aa0717a8a5e4859.tar.gz |
hide.h.m4: hide_functor::operator(): Make this variadic.
This uses some tuple manipulation utilities so that the variadic parameters
with which we call a method can be based on the variadic parameters that the
caller received, but not exactly. In this case, we need to replace an element
in the middle of a tuple. There is probably a more efficient way to do this.
For now, this is using copies of the tuple utilities from here:
https://github.com/murraycu/murrayc-tuple-utils/tree/master/tuple-utils
-rw-r--r-- | sigc++/adaptors/macros/hide.h.m4 | 88 |
1 files changed, 47 insertions, 41 deletions
diff --git a/sigc++/adaptors/macros/hide.h.m4 b/sigc++/adaptors/macros/hide.h.m4 index 0714c7a..b37cadc 100644 --- a/sigc++/adaptors/macros/hide.h.m4 +++ b/sigc++/adaptors/macros/hide.h.m4 @@ -22,46 +22,6 @@ define([ORDINAL],[dnl ifelse($1,0,,$1)ifelse($1,0,[last],$1,1,[st],$1,2,[nd],$1,3,[rd],[th])[]dnl ]) -define([HIDE_OPERATOR],[dnl -ifelse($2,0,,[dnl -ifelse($2,1,[dnl - /** Invokes the wrapped functor ignoring the only argument. - * @param _A_a1 Argument to be ignored. - * @return The return value of the functor invocation. - */ - template <class T_arg1> - decltype(auto) - operator()(T_arg1) - { return this->functor_(); } - -],$1,0,[dnl - /** Invokes the wrapped functor, ignoring the last argument.dnl -FOR(1, eval($2-1),[ - * @param _A_a%1 Argument to be passed on to the functor.]) - * @param _A_a$2 Argument to be ignored. - * @return The return value of the functor invocation. - */ - template <LOOP([class T_arg%1], $2)> - decltype(auto) - operator()(LOOP(T_arg%1 _A_a%1, eval($2-1)), T_arg$2) - { return this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<LIST(FOR(1,eval($2-1),[type_trait_pass_t<T_arg%1>,]))> - (LIST(FOR(1,eval($2-1),[_A_a%1,]))); } - -],[dnl - /** Invokes the wrapped functor, ignoring the ORDINAL($1) argument.dnl -FOR(1, eval($1-1),[ - * @param _A_a%1 Argument to be passed on to the functor.]) - * @param _A_a$1 Argument to be ignored.dnl -FOR(eval($1+1), $2,[ - * @param _A_a%1 Argument to be passed on to the functor.]) - * @return The return value of the functor invocation. - */ - template <LOOP([class T_arg%1], $2)> - decltype(auto) - operator()(LIST(FOR(1,eval($1-1),[T_arg%1 _A_a%1,]),T_arg$1,FOR(eval($1+1),$2,[T_arg%1 _A_a%1,]))) - { return this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<LIST(FOR(1,eval($1-1),[type_trait_pass_t<T_arg%1>,]),FOR(eval($1+1), $2,[type_trait_pass_t<T_arg%1>,]))> - (LIST(FOR(1,eval($1-1),[_A_a%1,]),FOR(eval($1+1),$2,[_A_a%1,]))); } - ])])dnl ])dnl end HIDE_OPERATOR @@ -79,7 +39,39 @@ struct hide_functor <$1, T_functor> : public adapts<T_functor> typedef typename adapts<T_functor>::adaptor_type adaptor_type; typedef typename adaptor_type::result_type result_type; -FOR(eval($1+1),CALL_SIZE,[[HIDE_OPERATOR(eval($1+1),%1)]])dnl + /** Invokes the wrapped functor, ignoring the ORDINAL($1) argument.dnl + * @param _A_a Arguments to be passed on to the functor, apart from the ORDINAL($1) argument. + * @return The return value of the functor invocation. + */ + template <class... T_arg> + decltype(auto) + operator()(T_arg... _A_a) + { + constexpr auto size = sizeof...(T_arg); + constexpr auto index_ignore = ($1 == -1 ? size - 1 : $1); + const auto t = std::make_tuple(_A_a...); + + const auto t_start = tuple_start<index_ignore>(t); + const auto t_end = tuple_end<size - index_ignore - 1>(t); + auto t_used = std::tuple_cat(t_start, t_end); //TODO: Let this be const? + + //This is so we can specify a particular instantiation of the functor's + //operator(). + //TODO: Avoid this if it no longer necessary. + using t_type = std::tuple<type_trait_pass_t<T_arg>...>; + using t_type_start = typename tuple_type_start<t_type, index_ignore>::type; + using t_type_end = typename tuple_type_end<t_type, size - index_ignore - 1>::type; + using t_type_used = typename tuple_type_cat<t_type_start, t_type_end>::type; + + constexpr auto size_used = size - 1; + + //TODO: Remove these? They are just here as a sanity check. + static_assert(std::tuple_size<t_type_used>::value == size_used, "Unexpected t_type_used size."); + static_assert(std::tuple_size<decltype(t_used)>::value == size_used, "Unexpected t_used size."); + + const auto seq = std::make_index_sequence<size_used>(); + return call_functor_operator_parentheses<t_type_used>(t_used, seq); + } /** Constructs a hide_functor object that adds a dummy parameter to the passed functor. * @param _A_func Functor to invoke from operator()(). @@ -87,6 +79,17 @@ FOR(eval($1+1),CALL_SIZE,[[HIDE_OPERATOR(eval($1+1),%1)]])dnl explicit hide_functor(const T_functor& _A_func) : adapts<T_functor>(_A_func) {} + +private: + //TODO_variadic: Replace this with std::experimental::apply() if that becomes standard + //C++, or add our own implementation, to avoid code duplication. + template<class T_tuple_specific, class T_tuple, std::size_t... Is> + decltype(auto) + call_functor_operator_parentheses(T_tuple& tuple, + std::index_sequence<Is...>) + { + return this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<typename std::tuple_element<Is, T_tuple_specific>::type...>(std::get<Is>(tuple)...); + } }; ifelse($1,eval(CALL_SIZE-1),[#endif // DOXYGEN_SHOULD_SKIP_THIS ],)dnl Include only the first two template specializations in the documentation. ($1 = -1..CALL_SIZE-1) @@ -96,6 +99,9 @@ ifelse($1,eval(CALL_SIZE-1),[#endif // DOXYGEN_SHOULD_SKIP_THIS divert(0)dnl _FIREWALL([ADAPTORS_HIDE]) #include <sigc++/adaptors/adaptor_trait.h> +#include <sigc++/tuple_cat.h> +#include <sigc++/tuple_end.h> +#include <sigc++/tuple_start.h> namespace sigc { |