From bc98bba2f302922761209c0e91485e809354abc1 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 1 Mar 2013 10:18:36 +0100 Subject: Support connection to functor with multiple operator() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When variadic templates and decltype are supported, detect the best overload of operator() to call. Currently, the code takes the type of the operator(), which requires that the functor only has one, and that it has no template parameter. This feature is required if we want to connect to c++1y generic lambda (N3418) Change-Id: Ifa957da6955ea39ab804b58f320da9f98ff47d63 Reviewed-by: Jędrzej Nowacki --- src/corelib/kernel/qobject.h | 34 ++++++++++++++++++++++++++++----- src/corelib/kernel/qobjectdefs_impl.h | 36 ++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 6 deletions(-) (limited to 'src/corelib/kernel') diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 7beaa32855..aaa09fac50 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Olivier Goffart ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -265,27 +266,50 @@ public: static inline typename QtPrivate::QEnableIf::ArgumentCount == -1, QMetaObject::Connection>::Type connect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, Func2 slot) { +#if defined (Q_COMPILER_DECLTYPE) && defined (Q_COMPILER_VARIADIC_TEMPLATES) + typedef QtPrivate::FunctionPointer SignalType; + const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount::Value; + + Q_STATIC_ASSERT_X((FunctorArgumentCount >= 0), + "Signal and slot arguments are not compatible."); + const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0; + typedef typename QtPrivate::FunctorReturnType::Value>::Value SlotReturnType; +#else + // Without variadic template, we don't detect the best overload of operator(). We just + // assume there is only one simple operator() and connect to &Func2::operator() + + /* If you get an error such as: + couldn't deduce template parameter 'Func2Operator' + or + cannot resolve address of overloaded function + It means the functor does not have a single operator(). + Functors with overloaded or templated operator() are only supported if the compiler supports + C++11 variadic templates + */ #ifndef Q_COMPILER_DECLTYPE //Workaround the lack of decltype using another function as indirection return connect_functor(sender, signal, slot, &Func2::operator()); } template static inline QMetaObject::Connection connect_functor(const QObject *sender, Func1 signal, Func2 slot, Func2Operator) { typedef QtPrivate::FunctionPointer SlotType ; #else - typedef QtPrivate::FunctionPointer SlotType ; #endif typedef QtPrivate::FunctionPointer SignalType; + typedef typename SlotType::ReturnType SlotReturnType; + const int SlotArgumentCount = SlotType::ArgumentCount; - Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), + Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= SlotArgumentCount, "The slot requires more arguments than the signal provides."); Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), "Signal and slot arguments are not compatible."); - Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), +#endif + + Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), "Return type of the slot is not compatible with the return type of the signal."); return connectImpl(sender, reinterpret_cast(&signal), sender, 0, - new QtPrivate::QFunctorSlotObject::Value, + new QtPrivate::QFunctorSlotObject::Value, typename SignalType::ReturnType>(slot), Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject); } diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index 46a6eab253..4f44d9204e 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Olivier Goffart ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -597,10 +598,43 @@ namespace QtPrivate { enum { value = AreArgumentsCompatible::Type, typename RemoveConstRef::Type>::value && CheckCompatibleArguments, List>::value }; }; +#endif + +#if defined(Q_COMPILER_DECLTYPE) && defined(Q_COMPILER_VARIADIC_TEMPLATES) + /* + Find the maximum number of arguments a functor object can take and be still compatible with + the arguments from the signal. + Value is the number of arguments, or -1 if nothing matches. + */ + template struct ComputeFunctorArgumentCount; + + template struct ComputeFunctorArgumentCountHelper + { enum { Value = -1 }; }; + template + struct ComputeFunctorArgumentCountHelper, false> + : ComputeFunctorArgumentCount, sizeof...(ArgList)>::Value> {}; + + template struct ComputeFunctorArgumentCount> + { + template static D dummy(); + template static auto test(F f) -> decltype(((f.operator()((dummy())...)), int())); + static char test(...); + enum { + Ok = sizeof(test(dummy())) == sizeof(int), + Value = Ok ? sizeof...(ArgList) : int(ComputeFunctorArgumentCountHelper, Ok>::Value) + }; + }; + /* get the return type of a functor, given the signal argument list */ + template struct FunctorReturnType; + template struct FunctorReturnType> { + template static D dummy(); + typedef decltype(dummy().operator()((dummy())...)) Value; + }; #endif -} +} QT_END_NAMESPACE -- cgit v1.2.3