#include <QObject>
#include "vlambda_p.h"
+/// @cond HIDDEN_CODE
+
/// Namespace for functions and sub-templates that are internal to the variadic lambda wrapper MVLambda.
namespace MVLambdaNS {
-/// \internal workarout for missing "final" keyword in GCC 4.6
+/// workarout for missing "final" keyword in GCC 4.6
//TODO: remove this as soon as "final" is available
class MVLFinal{protected:MVLFinal(){}};
-/// \internal base class for variadic lambda wrapper
+/// abstract base class for variadic lambda wrapper, simulates most of the Q_OBJECT macro
+/// you do not need to understand the details, unless you want to enhance it or fix bugs
class MVLambdaBase:public QObject
{
+ ///amount of parameters
const int m_count;
+ ///store the call-signature
const QByteArray m_callparm,m_callret;
+ ///pointers into the meta data
uint qt_meta_data[20];
+ ///the mata data of the artificial slot
QByteArray string_metadata;
+ ///the meta object of this instance, not static since it is calculated
QMetaObject meta_object;
+ ///overridden by the template to implement the actual call
virtual void do_call(void**)=0;
+ ///used by Qt to schedule a call
static void qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a);
+ ///simulated extra meta data of the lambda class in general
static const QMetaObjectExtraData staticMetaObjectExtraData;
protected:
-// MVLambdaBase(const MVLambdaBase&m):QObject(parent()),m_callname(m.m_callname){}
+ ///instantiates the instance, used by the template
MVLambdaBase ( int c,QByteArray rt, QByteArray cn, QObject* parent);
- const QByteArray callParams()const{return m_callparm;}
- const QByteArray callReturn()const{return m_callret;}
-
- /*static void qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
- {
- if (_c == QMetaObject::InvokeMetaMethod) {
- Q_ASSERT(staticMetaObject.cast(_o));
- MVLambda<Ret(Args...)> *_t = static_cast<MVLambda<Ret(Args...)> *>(_o);
- if (_id==0)MVLambdaNS::Call<Args...>(_a,_t->call();
- }
- Q_UNUSED(_a);
- }*/
public:
+ ///returns a pointer to the meta object of this instance (never manipulate it!)
const QMetaObject *metaObject() const{return &meta_object;}
+ ///cast function, used by Qt
void *qt_metacast(const char *_clname);
+ ///used by Qt to deliver a call
int qt_metacall(QMetaObject::Call _c, int _id, void **_a);
-
+
+ ///returns the parameter types of the call method
+ const QByteArray callParams()const{return m_callparm;}
+ ///returns the return type of the call method
+ const QByteArray callReturn()const{return m_callret;}
};
//end of namespace
};
+/// @endcond
+///forward declare the lambda wrapper template
template<typename _Signature>class MVLambda;
-///wrapper for simple lambda expression, so it can be used with signals
+/** \brief Wrapper for lambda expression, so it can be used with signals.
+
+This template allows to connect any lambda expression (or closure, function pointer, object method pointer or functor object) to a signal with compatible argument types by creating a slot with identical signature.
+
+In its simplest form the slot and lambda expression take no argument and return no values:
+\code
+int x=55;
+QPushButton button("Push me!");
+MVLambda<void()> lambda([&x](){qDebug()<<"x is"<<x;});
+connect(&button,SIGNAL(clicked()),&lambda,SLOT(call()));
+button.show();
+\endcode
+the above code will show the value of the variable 'x' whenever the user clicks the button.
+
+A more complex variation takes arguments and returns a value:
+\code
+MVLambda<int(double,int)> lambda([](double d,int i)->int{return d*i;});
+connect(&someobject,SIGNAL(mysig(double,int)),&lambda,SLOT(call(double,int)));
+...
+\endcode
+
+The wrapper object will automatically tell Qt about its virtual slot call(...) and will make sure it is called when a connected signal triggers. You can also request its meta object and inquire about its properties. Instances of this template are derived from QObject, so all functionality available in QObject is also available in lambda wrappers.
+
+\param Ret return type of the lambda being wrapped, also the return type of the generated slot
+\param Args variadic list of types of the argument list of the lambda and slot
+*/
template<typename Ret,typename...Args>
class MVLambda<Ret(Args...)> :public MVLambdaNS::MVLambdaBase,virtual private MVLambdaNS::MVLFinal
{
private:
+ ///function pointer...
std::function<Ret(Args...)>m_ptr;
- /// \internal interface for the Qt meta object system
+ /// interface for the Qt meta object system
virtual void do_call(void**a){
MVLambdaNS::Call<Ret(Args...)>(a,[&](Args...args)->Ret{return this->call(args...);});
}
public:
- ///instantiates the lambda object, e.g.
- /// \code
- ///int x=55;
- ///QPushButton button("Push me!");
- ///MLambda lambda([&x](){qDebug()<<"x is"<<x;});
- ///connect(&button,SIGNAL(clicked()),&lambda,SLOT(call()));
- ///button.show();
- /// \endcode
- ///the above code will show the value of the variable 'x' whenever the user clicks the button
+ ///instantiates the lambda wrapper object
+ /// \param l the lambda, closure, functor, function or method pointer to execute as a slot
+ /// \param parent optional: the parent object of this wrapper, you can use this to limit the lifetime of the wrapper object
MVLambda(std::function<Ret(Args...)>l,QObject* parent = 0)
:MVLambdaBase(MVLambdaNS::Count<Args...>::count, MVLambdaNS::TypeStr<Ret>::get(), MVLambdaNS::TypeStr<Args...>::get(), parent), m_ptr(l){}
- ///generic slot that transparently executes the lambda expression
+ ///overwrites the lambda/function that is executed as slot, this does
+ ///not alter signal-slot-connections
+ /// \param l new lambda, functor, function or method pointer
+ void setFunction(std::function<Ret(Args...)>l)
+ {m_ptr=l;}
+
+ ///Generic slot that transparently executes the lambda expression.
+ ///If the wrapper was initialized with a nullptr this slot will return a default constructed instance of the return type.
+ /// \param Args variadic list of arguments (depends on template parameters)
+ /// \returns an object of the configured return type - either the result of the lambda or a default constructed object
Ret call(Args...args){if(m_ptr)return m_ptr(args...);else return Ret();}
};
#include <QVariant>
#include <QByteArray>
+/// @cond HIDDEN_CODE
+
namespace MVLambdaNS {
-/// \internal helper for lambda template: determines the string representation of the functions type signature
+/// helper for lambda template: determines the string representation of the functions type signature
template<typename...A>class TypeStr;
+///recursive version: determines all typenames for more than one type in an argument list
template <typename F,typename...Args>
class TypeStr<F,Args...>{
public:
{return TypeStr<F>::get()+","+TypeStr<Args...>::get();}
};
+///determines name of a simple type
template <typename T>
class TypeStr<T>{
public: static const QByteArray get()
{T t;return QVariant::fromValue(t).typeName();}
};
+///determines name of a reference type
template <typename T>
class TypeStr<T&>{
public: static const QByteArray get()
{T t;return QByteArray(QVariant::fromValue(t).typeName())+"&";}
};
+///determine name of a const reference type
template <typename T>
class TypeStr<const T&>{
public: static const QByteArray get()
{T t;return QByteArray("const ")+QVariant::fromValue(t).typeName()+"&";}
};
+///determine name of a pointer type
template <typename T>
class TypeStr<T*>{
public: static const QByteArray get()
{T t;return QByteArray(QVariant::fromValue(t).typeName())+"*";}
};
+///determine name of a const pointer type
template <typename T>
class TypeStr<const T*>{
public: static const QByteArray get()
{T t;return QByteArray("const ")+QVariant::fromValue(t).typeName()+"*";}
};
+///fallback for no argument list: returns empty string
template<>
class TypeStr<>{
public: static const QByteArray get()
{return QByteArray();}
};
+///returns empty string for a void argument list
template<>
class TypeStr<void>{
public: static const QByteArray get()
//////////////////////////////////////////////////////
+///template to count an argument list
template<typename ...Args>class Count;
+///recursive version to count a list with at least one element
template<typename T,typename ...Args>
class Count<T,Args...>{public: static const int count=Count<Args...>::count + 1;};
+///fallback to count an empty argument list or to terminate a list
template<>
class Count<>{public: static const int count=0;};
+
+
+
///////////////////////////////////////////////////////
+///wrapper type to turn a Qt internal meta call into an actual method call - it turns a void** list into a typed argument list and a return argument
template<typename Sig>class Call;
+///turns a Qt internal meta call into a method call with return type and multiple arguments
template<typename R,typename T,typename...Args>
class Call<R(T,Args...)>
{
if(vl[0])*reinterpret_cast<R*>(vl[0])=r;
}
};
+///turns a Qt internal meta call into a method call with return type and a single argument
template<typename R,typename T>
class Call<R(T)>
{
if(vl[0])*reinterpret_cast<R*>(vl[0])=r;
}
};
+///turns a Qt internal meta call into a method call with return type and no arguments
template<typename R>
class Call<R()>
{
}
};
-
+///turns a Qt internal meta call into a method call returning void and multiple arguments
template<typename T,typename...Args>
class Call<void(T,Args...)>
{
Call<void(Args...)>(vl+1,[&](Args...args){cb(*reinterpret_cast<T*>(vl[1]),args...);});
}
};
+///turns a Qt internal meta call into a method call returning void and a single argument
template<typename T>
class Call<void(T)>
{
cb(*reinterpret_cast<T*>(vl[1]));
}
};
+///turns a Qt internal meta call into a method call returning void and no arguments
template<>
class Call<void()>
{
//end of namespace
};
+/// @endcond
+
#endif