I’m learning C++ (via Qt4) leveraging my python/pyqt4 experience, and I cannot seem to grasp the proper idiom for storing lambda expressions into a container for use as callbacks.
I have a struct with a bunch of fields. And I want to create a map of callbacks that can properly format the fields a specific way.
Here is the python equivalent of what I want to do:
from PyQt4.QtCore import QVariant, QString
class AType(object):
def __init__(self):
self.name = "FOO"
self.attr2 = "BAR"
self.attr3 = "BAZ"
# ...
callbacks = {}
callbacks['name'] = lambda x: QVariant(QString(x.name))
callbacks['attr2'] = lambda x: QVariant(QString(x.attr2))
callbacks['attr3'] = lambda x: QVariant(QString(x.attr3))
a = AType()
variant = callbacks['name'](a)
print variant.toString()
# PyQt4.QtCore.QString(u'FOO')
At first I found native lambdas in C++ and started trying it out, but then found that it is apparently a C++11 feature. Edit: I want to know if there is a pre C++11 approach before I start investigating whether I can introduce the flag into the build system for the project.
Then I looked at boost solutions. My project is already using boost, so I thought it might be a solution. I see there are both lambda and Phoenix options. To show that I have at least tried to make this work, here is my embarrassing failure:
## my_class.h ##
#include <QVariant>
#include <QMap>
#include <boost/function.hpp>
QMap< uint, boost::function<QVariant (AType&)> > callbacks;
## my_class.cpp ##
#include <boost/lambda/lambda.hpp>
#include <boost/bind/bind.hpp>
#include "my_class.h"
// I invite you to laugh at this
callbacks[0] = boost::bind(&QVariant, boost::bind(&QString::fromStdString, boost::bind(&AType::name, _1)));
After I wrote that last line, I realized I am spinning my wheels and better just ask more experience C++ developers about the idiomatic approach to creating a map of lambda callbacks (compatable with Qt).
My goal is to be able to take a known index and a known AType instance, and be able to return a proper format QVariant
Update
This is the solution I found to work, based on the accepted answer. Using C++98 compatible solution.
#include <QMap>
#include <QVariant>
#include <QString>
#include <QDebug>
struct AType {
AType();
std::string name, attr2, attr3;
};
AType::AType() {
name = "FOO";
attr2 = "BAR";
attr3 = "BAZ";
}
typedef QMap< QString, QVariant (*)( AType const& ) > Callbacks;
struct ATypeFieldMapper
{
static QVariant name( AType const& x )
{ return QVariant(QString::fromStdString(x.name)); }
static QVariant attr2( AType const& x )
{ return QVariant(QString::fromStdString(x.attr2)); }
static QVariant attr3( AType const& x )
{ return QVariant(QString::fromStdString(x.attr3)); }
};
int main()
{
Callbacks callbacks;
callbacks["name"] = &ATypeFieldMapper::name;
callbacks["attr2"] = &ATypeFieldMapper::attr2;
callbacks["attr3"] = &ATypeFieldMapper::attr3;
AType a;
qDebug() << callbacks["name"](a).toString();
qDebug() << callbacks["attr2"](a).toString();
qDebug() << callbacks["attr3"](a).toString();
}
//"FOO"
//"BAR"
//"BAZ"
In C++ a lambda is nothing but syntactic sugar, that allows you to write functor definitions inline. A functor is an object with an
operator(). So if you can’t use C++11 (one reason might be because you’re forced to use an old compiler?) then you can always just define functor classes, or if those conceptual lambdas don’t capture anything, then you can just use plain old functions.🙂
Kay, I’m going to write up an example. Just a few minutes…
Here goes…
Disclaimer: untested code (except that it compiles with msvc and mingw g++).