/** * Copyright 2015 Denis Blank * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * 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_