19 #if !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
21 # ifndef IN_QGLIB_CONNECT_H
22 # error "This file must not be included directly"
26 # include "refpointer.h"
27 # include <QtCore/QList>
29 # include <boost/type_traits.hpp>
37 template <
typename Function,
typename Signature>
43 template <
typename Function,
typename R>
46 static inline void invoke(
const Function & f, Value & result) { ValueImpl<R>::set(result, f()); }
49 template <
typename Function>
50 struct invoker<Function, void>
52 static inline void invoke(
const Function & f, Value &) { f(); }
68 template <
typename T,
typename R,
typename... Args>
72 inline MemberFunction(R (T::*fn)(Args...), T *obj)
73 : m_function(fn), m_object(obj) {}
75 inline R operator()(Args&&... args)
const
77 return (m_object->*m_function)(std::forward<Args>(args)...);
81 R (T::*m_function)(Args...);
85 template <
typename T,
typename R,
typename... Args>
86 MemberFunction<T, R, Args...> mem_fn(R (T::*fn)(Args...), T *obj)
88 return MemberFunction<T, R, Args...>(fn, obj);
94 template <
typename ParentFunction,
typename R,
typename Arg1,
typename... Args>
95 class BoundArgumentFunction
98 inline BoundArgumentFunction(ParentFunction && fn, Arg1 && arg)
99 : m_function(std::forward<ParentFunction>(fn)),
100 m_firstArg(std::forward<Arg1>(arg)) {}
102 inline R operator()(Args&&... args)
const
104 return m_function(std::forward<Arg1>(m_firstArg), std::forward<Args>(args)...);
108 ParentFunction && m_function;
112 template <
typename F,
typename R,
typename Arg1,
typename... Args>
113 inline BoundArgumentFunction<F, R, Arg1, Args...> partial_bind(F && f, Arg1 && a1)
115 return BoundArgumentFunction<F, R, Arg1, Args...>(std::forward<F>(f), std::forward<Arg1>(a1));
121 template <
typename F,
typename R>
122 inline void unpackAndInvoke(F &&
function, Value & result,
123 QList<Value>::const_iterator &&,
124 QList<Value>::const_iterator &&)
126 invoker<F, R>::invoke(
function, result);
129 template <
typename F,
typename R,
typename Arg1,
typename... Args>
130 inline void unpackAndInvoke(F &&
function, Value & result,
131 QList<Value>::const_iterator && argsBegin,
132 QList<Value>::const_iterator && argsEnd)
134 typedef typename boost::remove_const<
135 typename boost::remove_reference<Arg1>::type
137 typedef BoundArgumentFunction<F, R, Arg1, Args...> F1;
139 CleanArg1 && boundArg = ValueImpl<CleanArg1>::get(*argsBegin);
140 F1 && f = partial_bind<F, R, Arg1, Args...>(std::forward<F>(
function), std::forward<Arg1>(boundArg));
142 unpackAndInvoke< F1, R, Args... >(std::forward<F1>(f), result,
143 std::forward<QList<Value>::const_iterator>(++argsBegin),
144 std::forward<QList<Value>::const_iterator>(argsEnd));
150 template <
typename F,
typename R,
typename... Args>
151 struct CppClosure<F, R (Args...)>
153 class ClosureData :
public ClosureDataBase
156 inline ClosureData(
const F & func,
bool passSender)
157 : ClosureDataBase(passSender), m_function(func) {}
159 virtual void marshaller(Value & result,
const QList<Value> & params)
161 if (static_cast<unsigned int>(params.size()) <
sizeof...(Args)) {
162 throw std::logic_error(
"The signal provides less arguments than what the closure expects");
165 unpackAndInvoke<F, R, Args...>(std::forward<F>(m_function), result,
166 params.constBegin(), params.constEnd());
173 static inline ClosureDataBase *create(
const F &
function,
bool passSender)
175 return new ClosureData(
function, passSender);
185 template <
typename T,
typename R,
typename... Args>
186 bool connect(
void *instance,
const char *detailedSignal,
187 T *receiver, R (T::*slot)(Args...), ConnectFlags flags = 0)
189 typedef Private::MemberFunction<T, R, Args...> F;
191 F && f = Private::mem_fn(slot, receiver);
192 Private::ClosureDataBase* && closure
193 = Private::CppClosure<F, R (Args...)>::create(f, flags &
PassSender);
195 return Private::connect(instance, detailedSignal,
Quark(),
196 receiver, Private::GetDestroyNotifier<T>(),
197 Private::hashMfp(slot), closure, flags);
204 # else //QGLIB_HAVE_CXX0X
206 # include <boost/function.hpp>
207 # include <boost/preprocessor.hpp>
208 # include <boost/bind.hpp>
211 # define BOOST_PP_ITERATION_PARAMS_1 (3,(0, QGLIB_CONNECT_MAX_ARGS, "QGlib/connectimpl.h"))
212 # include BOOST_PP_ITERATE()
214 # undef BOOST_PP_ITERATION_PARAMS_1
215 # undef QGLIB_CONNECT_MAX_ARGS
217 # endif //QGLIB_HAVE_CXX0X
220 #else // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
231 # define QGLIB_CONNECT_IMPL_NUM_ARGS \
234 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS \
235 BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, typename A)
237 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS \
238 BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
240 # define QGLIB_CONNECT_IMPL_TEMPLATE_ARGS \
241 BOOST_PP_ENUM_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
248 # define QGLIB_CONNECT_IMPL_CPPCLOSUREN \
249 BOOST_PP_CAT(CppClosure, QGLIB_CONNECT_IMPL_NUM_ARGS)
251 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP(z, n, list) \
253 typename boost::remove_const< \
254 typename boost::remove_reference<A ##n>::type \
258 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS(list) \
259 BOOST_PP_REPEAT(QGLIB_CONNECT_IMPL_NUM_ARGS, QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP, list)
261 template <
typename F,
typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
262 struct QGLIB_CONNECT_IMPL_CPPCLOSUREN
264 class ClosureData :
public ClosureDataBase
267 inline ClosureData(
const F & func,
bool passSender)
268 : ClosureDataBase(passSender), m_function(func) {}
270 virtual void marshaller(Value & result,
const QList<Value> & params)
272 if (params.size() < QGLIB_CONNECT_IMPL_NUM_ARGS) {
273 throw std::logic_error(
"The signal provides less arguments than what the closure expects");
276 # if QGLIB_CONNECT_IMPL_NUM_ARGS > 0
277 boost::function<R ()> callback = boost::bind<R>(m_function
278 QGLIB_CONNECT_IMPL_UNPACK_ARGS(params));
279 invoker< boost::function<R ()>, R >::invoke(callback, result);
281 invoker< F, R >::invoke(m_function, result);
289 static ClosureDataBase *create(
const F &
function,
bool passSender)
291 return new ClosureData(
function, passSender);
296 template <
typename F,
typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
297 struct CppClosure<F, R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>
298 :
public QGLIB_CONNECT_IMPL_CPPCLOSUREN< F, R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS >
302 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS
303 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP
304 # undef QGLIB_CONNECT_IMPL_CPPCLOSUREN
312 # define QGLIB_CONNECT_IMPL_BIND_ARGS \
313 BOOST_PP_COMMA_IF(QGLIB_CONNECT_IMPL_NUM_ARGS) \
314 BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(QGLIB_CONNECT_IMPL_NUM_ARGS), _)
316 template <
typename T,
typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
317 bool connect(
void *instance,
const char *detailedSignal,
318 T *receiver, R (T::*slot)(QGLIB_CONNECT_IMPL_TEMPLATE_ARGS), ConnectFlags flags = 0)
320 boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)> f
321 = boost::bind(slot, receiver QGLIB_CONNECT_IMPL_BIND_ARGS);
323 Private::ClosureDataBase *closure = Private::CppClosure<
324 boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>,
325 R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)
328 return Private::connect(instance, detailedSignal, Quark(),
329 receiver, Private::GetDestroyNotifier<T>(),
330 Private::hashMfp(slot), closure, flags);
333 # undef QGLIB_CONNECT_IMPL_BIND_ARGS
339 # undef QGLIB_CONNECT_IMPL_TEMPLATE_ARGS
340 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS
341 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS
342 # undef QGLIB_CONNECT_IMPL_NUM_ARGS
344 #endif // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING