/*! * \file utl/utility/invoke.h * \brief invoke() and invoke traits implementation * * Copyright (C) 2018-2019 Christos Choutouridis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more detail. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef __utl_utility_invoke_h__ #define __utl_utility_invoke_h__ #include #include #include #include #include /*! * \ingroup utility * \defgroup invoke */ //! @{ namespace utl { namespace detail { template struct is_ref_wrapper : meta::false_ {}; template struct is_ref_wrapper> : meta::true_ {}; // 1 template >::value && std::is_base_of>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return (std::forward(t1).*f)(std::forward(args)...); } // 2 template >::value && is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return (t1.get().*f)(std::forward(args)...); } // 3 template >::value && !std::is_base_of>::value && !is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return ((*std::forward(t1)).*f)(std::forward(args)...); } // 4 template >::value && std::is_base_of>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return std::forward(t1).*f; } // 5 template >::value && is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return t1.get().*f; } // 6 template >::value && !std::is_base_of>::value && !is_ref_wrapper>::value, int> =0 > decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { return (*std::forward(t1)).*f; } template decltype(auto) invoke_impl_(F&& f, Args&&... args) { return std::forward(f)(std::forward(args)...); } } // namespace detail //! Invoke a callable object (for C++14) template inline decltype(auto) invoke(_Callable&& fn, _Args&&... args) { return detail::invoke_impl_( std::forward<_Callable>(fn), std::forward<_Args>(args)... ); } //! @} //! std::is_invocable trait for C++11 template struct is_invocable : std::is_constructible< std::function, std::reference_wrapper::type> > { }; //! std::is_invocable_r trait for C++11 template struct is_invocable_r : std::is_constructible< std::function, std::reference_wrapper::type> > { }; /*! * invoke_result (SFINAE friendly) */ //! @{ namespace detail { template struct try_invoke { using type = decltype ( detail::invoke_impl_(std::declval<_Callable&&>(), std::declval<_Args&&>()...) ); }; template struct invoke_result_ { using type = meta::nil_; }; template struct invoke_result_ { using type = meta::invoke_t< meta::quote, _Callable, _Args... >; }; } //! invoke_result (for C++14) template using invoke_result = detail::invoke_result_< is_invocable<_Callable, _Args...>::value, _Callable, _Args... >; //! invoke_result_t (for C++14) template using invoke_result_t = meta::eval < invoke_result<_Callable, _Args...> >; } //! @} #endif /* __utl_utility_invoke_h__ */