/* * Copyright (C) 2015 Naios * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * The functional unwrap trait provides the possibility to extract * various types out of c++ functional types, like std::function, functors and more. */ #ifndef _FUNCTIONAL_UNWRAP_HPP_ #define _FUNCTIONAL_UNWRAP_HPP_ #include #include #include #include namespace fu { /// Identity class which is used to carry parameter packs of types. template struct identity { }; /// Sequence class which is used to carry parameter packs of unsigned integers. template struct sequence { }; /// The Sequence generator generates a sequence of ascending numbers with the given size. template struct sequence_generator; template struct sequence_generator<0, Stack...> { typedef sequence type; }; template struct sequence_generator : sequence_generator { }; /// Sequence generator alias template using sequence_of_t = typename sequence_generator::type; namespace detail { template struct unwrap_function_impl; template struct unwrap_function_impl<_RTy(_ATy...)> { /// The return type of the function. typedef _RTy return_type; /// The argument types of the function as pack in fu::identity. typedef identity<_ATy...> argument_type; /// The function provided as std::function typedef std::function<_RTy(_ATy...)> function_type; /// The function provided as function_ptr typedef _RTy(*function_ptr)(_ATy...); }; /// Pack in fu::identity template struct unwrap_function_impl> : unwrap_function_impl<_RTy(_ATy...)> { }; /// STL: std::function template struct unwrap_function_impl> : unwrap_function_impl<_RTy(_ATy...)> { }; /// STL: std::tuple template struct unwrap_function_impl> : unwrap_function_impl<_RTy(_ATy...)> { }; /// Const function pointers template struct unwrap_function_impl<_RTy(*const)(_ATy...)> : unwrap_function_impl<_RTy(_ATy...)> { }; /// Mutable function pointers template struct unwrap_function_impl<_RTy(*)(_ATy...)> : unwrap_function_impl<_RTy(_ATy...)> { }; /// Const class method pointers template struct unwrap_function_impl<_RTy(_CTy::*)(_ATy...) const> : unwrap_function_impl<_RTy(_ATy...)> { }; /// Mutable class method pointers template struct unwrap_function_impl<_RTy(_CTy::*)(_ATy...)> : unwrap_function_impl<_RTy(_ATy...)> { }; /// Unwrap through pointer of functor. template static auto select_best_unwrap_unary_arg(int) -> unwrap_function_impl; /// Unwrap through plain type. template static auto select_best_unwrap_unary_arg(long) -> unwrap_function_impl; template struct select_best_unwrap; /// Enable only if 1 template argument is given. template struct select_best_unwrap<_FTy> { typedef decltype(select_best_unwrap_unary_arg<_FTy>(0)) type; }; // Enable if more then 1 template argument is given. // (Handles lazy typing) template struct select_best_unwrap<_RTy, _ATy...> { typedef unwrap_function_impl<_RTy(_ATy...)> type; }; template struct to_true : std::true_type { }; /// std::true_type if unwrappable template static auto test_unwrappable(int) -> to_true::type::function_type>; /// std::false_type if not unwrappable template static auto test_unwrappable(long) -> std::false_type; } // detail /// Trait to unwrap function parameters of various types: /// Function style definition: Result(Parameters...) /// STL `std::function` : std::function /// STL `std::tuple` : std::tuple /// C++ Function pointers: `Result(*)(Parameters...)` /// C++ Class method pointers: `Result(Class::*)(Parameters...)` /// Lazy typed signatures: `Result, Parameters...` /// Also provides optimized unwrap of functors and functional objects. template using unwrap_function = typename detail::select_best_unwrap::type; /// Trait which defines the return type of the function. template using return_type_of_t = typename detail::select_best_unwrap::type::return_type; /// Trait which defines the argument types of the function packed in std::tuple. template using argument_type_of_t = typename detail::select_best_unwrap::type::argument_type; /// Trait which defines the std::function type of the function. template using function_type_of_t = typename detail::select_best_unwrap::type::function_type; /// Trait which defines the function pointer type of the function. template using function_ptr_of_t = typename detail::select_best_unwrap::type::function_ptr; /// Trait which defines if the given function is unwrappable or not. template struct is_unwrappable : decltype(detail::test_unwrappable(0)) { }; /// Converts any functional type in std::function. template auto functionfy(Functional&& functional) -> function_type_of_t::type> { return function_type_of_t::type>(std::forward(functional)); } template struct requires_functional_constructible { static_assert(is_unwrappable::type>::value, "Given type is not functional unwrappable, did you try to use a std::bind expression or a non functional type?"); typedef T type; }; namespace detail { /// Implementation of invoke_from_tuple template struct invoker; template struct invoker> { template inline static void silencer(_TTy&&) { } template inline static auto invoke(_FTy&& functional, _TTy&& tuple) -> return_type_of_t::type> { // Silences warnings about unreferenced formal parameter when pack is empty. silencer(tuple); return std::forward<_FTy>(functional)(std::get(std::forward<_TTy>(tuple))...); } }; } /// Invokes a function type with the given tuple arguments. template inline auto invoke_from_tuple(_FTy&& functional, _TTy&& tuple) -> return_type_of_t::type> { return detail::invoker< sequence_of_t< std::tuple_size< typename std::decay<_TTy>::type >::value > >::invoke(std::forward<_FTy>(functional), std::forward<_TTy>(tuple)); } } // fu #endif // _FUNCTIONAL_UNWRAP_HPP_