blob: 27d18b40b4879912443600089008fb426dd2b811 [file] [log] [blame]
Wenzel Jakob38bd7112015-07-05 20:05:44 +02001/*
2 pybind/mpl.h: Simple library for type manipulation and template metaprogramming
3
4 Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
5
6 All rights reserved. Use of this source code is governed by a
7 BSD-style license that can be found in the LICENSE file.
8*/
9
Wenzel Jakobbd4a5292015-07-11 17:41:48 +020010#pragma once
Wenzel Jakob38bd7112015-07-05 20:05:44 +020011
Wenzel Jakobbd4a5292015-07-11 17:41:48 +020012#include <pybind/common.h>
Wenzel Jakob38bd7112015-07-05 20:05:44 +020013#include <tuple>
14
15NAMESPACE_BEGIN(pybind)
16NAMESPACE_BEGIN(mpl)
17
18/// Index sequence for convenient template metaprogramming involving tuples
19template<size_t ...> struct index_sequence { };
20template<size_t N, size_t ...S> struct make_index_sequence : make_index_sequence <N - 1, N - 1, S...> { };
21template<size_t ...S> struct make_index_sequence <0, S...> { typedef index_sequence<S...> type; };
22
23/// Helper template to strip away type modifiers
24template <typename T> struct normalize_type { typedef T type; };
25template <typename T> struct normalize_type<const T> { typedef typename normalize_type<T>::type type; };
26template <typename T> struct normalize_type<T*> { typedef typename normalize_type<T>::type type; };
27template <typename T> struct normalize_type<T&> { typedef typename normalize_type<T>::type type; };
28template <typename T> struct normalize_type<T&&> { typedef typename normalize_type<T>::type type; };
29template <typename T, size_t N> struct normalize_type<const T[N]> { typedef typename normalize_type<T>::type type; };
30template <typename T, size_t N> struct normalize_type<T[N]> { typedef typename normalize_type<T>::type type; };
31
32NAMESPACE_BEGIN(detail)
33
34/// Strip the class from a method type
35template <typename T> struct remove_class {};
36template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
37template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); };
38
39/**
40 * \brief Convert a lambda function to a std::function
41 * From http://stackoverflow.com/questions/11893141/inferring-the-call-signature-of-a-lambda-or-arbitrary-callable-for-make-functio
42 */
43template <typename T> struct lambda_signature_impl {
44 using type = typename remove_class<
45 decltype(&std::remove_reference<T>::type::operator())>::type;
46};
47template <typename R, typename... A> struct lambda_signature_impl<R (A...)> { typedef R type(A...); };
48template <typename R, typename... A> struct lambda_signature_impl<R (&)(A...)> { typedef R type(A...); };
49template <typename R, typename... A> struct lambda_signature_impl<R (*)(A...)> { typedef R type(A...); };
50template <typename T> using lambda_signature = typename lambda_signature_impl<T>::type;
51template <typename F> using make_function_type = std::function<lambda_signature<F>>;
52
53NAMESPACE_END(detail)
54
55template<typename F> detail::make_function_type<F> make_function(F &&f) {
56 return detail::make_function_type<F>(std::forward<F>(f)); }
57
58NAMESPACE_BEGIN(detail)
59
60struct void_type { };
61
62/// Helper functions for calling a function using a tuple argument while dealing with void/non-void return values
63template <typename RetType> struct tuple_dispatch {
64 typedef RetType return_type;
65 template<typename Func, typename Arg, size_t ... S> return_type operator()(const Func &f, Arg && args, index_sequence<S...>) {
66 return f(std::get<S>(std::forward<Arg>(args))...);
67 }
68};
69
70/// Helper functions for calling a function using a tuple argument (special case for void return values)
71template <> struct tuple_dispatch<void> {
72 typedef void_type return_type;
73 template<typename Func, typename Arg, size_t ... S> return_type operator()(const Func &f, Arg &&args, index_sequence<S...>) {
74 f(std::get<S>(std::forward<Arg>(args))...);
75 return return_type();
76 }
77};
78
79NAMESPACE_END(detail)
80
81/// For lambda functions delegate to their 'operator()'
Wenzel Jakobbd4a5292015-07-11 17:41:48 +020082template <typename T> struct function_traits : function_traits<typename detail::make_function_type<T>> { };
83
84/* Deal with reference arguments */
85template <typename ReturnType, typename... Args>
86 struct function_traits<ReturnType(*&)(Args...)> : function_traits<ReturnType(*)(Args...)> {};
87template <typename ClassType, typename ReturnType, typename... Args>
88 struct function_traits<ReturnType(ClassType::*&)(Args...)> : function_traits<ReturnType(ClassType::*)(Args...)> {};
89template <typename ClassType, typename ReturnType, typename... Args>
90 struct function_traits<ReturnType(ClassType::*&)(Args...) const> : function_traits<ReturnType(ClassType::*)(Args...) const> {};
Wenzel Jakob38bd7112015-07-05 20:05:44 +020091
92/// Type traits for function pointers
93template <typename ReturnType, typename... Args>
94struct function_traits<ReturnType(*)(Args...)> {
95 enum {
96 nargs = sizeof...(Args),
97 is_method = 0,
98 is_const = 0
99 };
100 typedef std::function<ReturnType (Args...)> f_type;
101 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
102 typedef typename dispatch_type::return_type return_type;
103 typedef std::tuple<Args...> args_type;
104
105 template <size_t i> struct arg {
106 typedef typename std::tuple_element<i, args_type>::type type;
107 };
108
109 static f_type cast(ReturnType (*func)(Args ...)) { return func; }
110
111 static return_type dispatch(const f_type &f, args_type &&args) {
112 return dispatch_type()(f, std::move(args),
113 typename make_index_sequence<nargs>::type());
114 }
115};
116
117/// Type traits for ordinary methods
118template <typename ClassType, typename ReturnType, typename... Args>
119struct function_traits<ReturnType(ClassType::*)(Args...)> {
120 enum {
121 nargs = sizeof...(Args),
122 is_method = 1,
123 is_const = 0
124 };
125 typedef std::function<ReturnType(ClassType &, Args...)> f_type;
126 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
127 typedef typename dispatch_type::return_type return_type;
128 typedef std::tuple<ClassType&, Args...> args_type;
129
130 template <size_t i> struct arg {
131 typedef typename std::tuple_element<i, args_type>::type type;
132 };
133
134 static f_type cast(ReturnType (ClassType::*func)(Args ...)) { return std::mem_fn(func); }
135
136 static return_type dispatch(const f_type &f, args_type &&args) {
137 return dispatch_type()(f, std::move(args),
138 typename make_index_sequence<nargs+1>::type());
139 }
140};
141
142/// Type traits for const methods
143template <typename ClassType, typename ReturnType, typename... Args>
144struct function_traits<ReturnType(ClassType::*)(Args...) const> {
145 enum {
146 nargs = sizeof...(Args),
147 is_method = 1,
148 is_const = 1
149 };
150 typedef std::function<ReturnType (const ClassType &, Args...)> f_type;
151 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
152 typedef typename dispatch_type::return_type return_type;
153 typedef std::tuple<const ClassType&, Args...> args_type;
154
155 template <size_t i> struct arg {
156 typedef typename std::tuple_element<i, args_type>::type type;
157 };
158
159 static f_type cast(ReturnType (ClassType::*func)(Args ...) const) {
160 return std::mem_fn(func);
161 }
162
163 static return_type dispatch(const f_type &f, args_type &&args) {
164 return dispatch_type()(f, std::move(args),
165 typename make_index_sequence<nargs+1>::type());
166 }
167};
168
169/// Type traits for std::functions
170template <typename ReturnType, typename... Args>
171struct function_traits<std::function<ReturnType(Args...)>> {
172 enum {
173 nargs = sizeof...(Args),
174 is_method = 0,
175 is_const = 0
176 };
177 typedef std::function<ReturnType (Args...)> f_type;
178 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
179 typedef typename dispatch_type::return_type return_type;
180 typedef std::tuple<Args...> args_type;
181
182 template <size_t i> struct arg {
183 typedef typename std::tuple_element<i, args_type>::type type;
184 };
185
186 static f_type cast(const f_type &func) { return func; }
187
188 static return_type dispatch(const f_type &f, args_type &&args) {
189 return dispatch_type()(f, std::move(args),
190 typename make_index_sequence<nargs>::type());
191 }
192};
193
194NAMESPACE_END(mpl)
195NAMESPACE_END(pybind)