/* pybind/mpl.h: Simple library for type manipulation and template metaprogramming Copyright (c) 2015 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #pragma once #include #include NAMESPACE_BEGIN(pybind) NAMESPACE_BEGIN(mpl) /// Index sequence for convenient template metaprogramming involving tuples template struct index_sequence { }; template struct make_index_sequence : make_index_sequence { }; template struct make_index_sequence <0, S...> { typedef index_sequence type; }; /// Helper template to strip away type modifiers template struct normalize_type { typedef T type; }; template struct normalize_type { typedef typename normalize_type::type type; }; template struct normalize_type { typedef typename normalize_type::type type; }; template struct normalize_type { typedef typename normalize_type::type type; }; template struct normalize_type { typedef typename normalize_type::type type; }; template struct normalize_type { typedef typename normalize_type::type type; }; template struct normalize_type { typedef typename normalize_type::type type; }; NAMESPACE_BEGIN(detail) /// Strip the class from a method type template struct remove_class {}; template struct remove_class { typedef R type(A...); }; template struct remove_class { typedef R type(A...); }; /** * \brief Convert a lambda function to a std::function * From http://stackoverflow.com/questions/11893141/inferring-the-call-signature-of-a-lambda-or-arbitrary-callable-for-make-functio */ template struct lambda_signature_impl { using type = typename remove_class< decltype(&std::remove_reference::type::operator())>::type; }; template struct lambda_signature_impl { typedef R type(A...); }; template struct lambda_signature_impl { typedef R type(A...); }; template struct lambda_signature_impl { typedef R type(A...); }; template using lambda_signature = typename lambda_signature_impl::type; template using make_function_type = std::function>; NAMESPACE_END(detail) template detail::make_function_type make_function(F &&f) { return detail::make_function_type(std::forward(f)); } NAMESPACE_BEGIN(detail) struct void_type { }; /// Helper functions for calling a function using a tuple argument while dealing with void/non-void return values template struct tuple_dispatch { typedef RetType return_type; template return_type operator()(const Func &f, Arg && args, index_sequence) { return f(std::get(std::forward(args))...); } }; /// Helper functions for calling a function using a tuple argument (special case for void return values) template <> struct tuple_dispatch { typedef void_type return_type; template return_type operator()(const Func &f, Arg &&args, index_sequence) { f(std::get(std::forward(args))...); return return_type(); } }; NAMESPACE_END(detail) /// For lambda functions delegate to their 'operator()' template struct function_traits : function_traits> { }; /* Deal with reference arguments */ template struct function_traits : function_traits {}; template struct function_traits : function_traits {}; template struct function_traits : function_traits {}; /// Type traits for function pointers template struct function_traits { enum { nargs = sizeof...(Args), is_method = 0, is_const = 0 }; typedef std::function f_type; typedef detail::tuple_dispatch dispatch_type; typedef typename dispatch_type::return_type return_type; typedef std::tuple args_type; template struct arg { typedef typename std::tuple_element::type type; }; static f_type cast(ReturnType (*func)(Args ...)) { return func; } static return_type dispatch(const f_type &f, args_type &&args) { return dispatch_type()(f, std::move(args), typename make_index_sequence::type()); } }; /// Type traits for ordinary methods template struct function_traits { enum { nargs = sizeof...(Args), is_method = 1, is_const = 0 }; typedef std::function f_type; typedef detail::tuple_dispatch dispatch_type; typedef typename dispatch_type::return_type return_type; typedef std::tuple args_type; template struct arg { typedef typename std::tuple_element::type type; }; static f_type cast(ReturnType (ClassType::*func)(Args ...)) { return std::mem_fn(func); } static return_type dispatch(const f_type &f, args_type &&args) { return dispatch_type()(f, std::move(args), typename make_index_sequence::type()); } }; /// Type traits for const methods template struct function_traits { enum { nargs = sizeof...(Args), is_method = 1, is_const = 1 }; typedef std::function f_type; typedef detail::tuple_dispatch dispatch_type; typedef typename dispatch_type::return_type return_type; typedef std::tuple args_type; template struct arg { typedef typename std::tuple_element::type type; }; static f_type cast(ReturnType (ClassType::*func)(Args ...) const) { return std::mem_fn(func); } static return_type dispatch(const f_type &f, args_type &&args) { return dispatch_type()(f, std::move(args), typename make_index_sequence::type()); } }; /// Type traits for std::functions template struct function_traits> { enum { nargs = sizeof...(Args), is_method = 0, is_const = 0 }; typedef std::function f_type; typedef detail::tuple_dispatch dispatch_type; typedef typename dispatch_type::return_type return_type; typedef std::tuple args_type; template struct arg { typedef typename std::tuple_element::type type; }; static f_type cast(const f_type &func) { return func; } static return_type dispatch(const f_type &f, args_type &&args) { return dispatch_type()(f, std::move(args), typename make_index_sequence::type()); } }; NAMESPACE_END(mpl) NAMESPACE_END(pybind)