qt — Python — & gt; Идиома C ++: Хранение лямбда-выражений в карте / контейнере

Я изучаю C ++ (через Qt4), используя свой опыт работы с python / pyqt4, и я не могу понять, как правильно хранить лямбда-выражения в контейнере для использования в качестве обратных вызовов.

У меня есть структура с кучей полей. И я хочу создать карту обратных вызовов, которые могут правильно форматировать поля определенным образом.

Вот Python-эквивалент того, что я хочу сделать:

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')

Сначала я нашел нативные лямбды в C ++ и начал их пробовать, но потом обнаружил, что это, очевидно, функция C ++ 11. Редактировать: Я хочу знать, есть ли подход до C ++ 11, прежде чем я начну исследовать, могу ли я ввести флаг в систему сборки для проекта.

Затем я посмотрел на решения для повышения. Мой проект уже использует boost, поэтому я подумал, что это может быть решением. Я вижу, что есть оба lambda а также Phoenix опции. Чтобы показать, что я хотя бы попытался сделать эту работу, вот моя смущающая ошибка:

## 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)));

После того, как я написал эту последнюю строку, я понял, что я крутлю свои колеса и лучше просто спросить больше опытных разработчиков на C ++ о идиоматическом подходе к созданию карты лямбда-обратных вызовов (совместимых с Qt).

Моя цель состоит в том, чтобы иметь возможность взять известный индекс и известный AType экземпляр и сможет вернуть правильный формат QVariant

Обновить

Это решение, которое я нашел для работы, основано на принятом ответе. Использование C ++ 98 совместимого решения.

#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"

4

Решение

В C ++ лямбда — это не что иное, как синтаксический сахар, который позволяет вам писать встроенные определения функторов. функтор это объект с operator(), Поэтому, если вы не можете использовать C ++ 11 (одна из причин может быть из-за того, что вы вынуждены использовать старый компилятор?), Тогда вы всегда можете просто определить классы функторов, или если эти концептуальные лямбды ничего не захватывают, тогда вы можно просто использовать простые старые функции.

🙂

Кей, я собираюсь написать пример. Всего несколько минут …


Вот оно…

struct QString{ QString( wchar_t const* ){} };
struct QVariant { QVariant( QString const& ) {} };
struct AType{ wchar_t const* name() const { return L""; } };

#include <functional>       // std::function
#include <map>              // std::map
#include <string>           // std::wstring
using namespace std;

void cpp11()
{
typedef map< wstring, function< QVariant( AType const& ) > > Callbacks;
Callbacks callbacks;
callbacks[L"name"] = []( AType const& x )
{ return QVariant( QString( x.name() ) ); };

auto const a = AType();
auto variant = callbacks[L"name"]( a );
}

void cpp03Limited()
{
typedef map< wstring, QVariant (*)( AType const& ) > Callbacks;
Callbacks callbacks;

struct SimpleConversion
{
static QVariant convert( AType const& x )
{ return QVariant( QString( x.name() ) ); }
};

callbacks[L"name"] = &SimpleConversion::convert;

AType const a = AType();
QVariant const variant = callbacks[L"name"]( a );
}

void cpp03General()
{
struct IConversion
{
virtual QVariant convert( AType const& ) const = 0;
};

struct ConversionInvoker
{
IConversion const*  pConverter;

QVariant operator()( AType const& x ) const
{
return pConverter->convert( x );
}

explicit ConversionInvoker( IConversion const* const p = 0 )
: pConverter( p )
{}
};

typedef map< wstring, ConversionInvoker > Callbacks;
Callbacks callbacks;

struct SimpleConversion: IConversion
{
virtual QVariant convert( AType const& x ) const
{ return QVariant( QString( x.name() ) ); }
};
SimpleConversion const simpleConversionFunc;

callbacks[L"name"] = ConversionInvoker( &simpleConversionFunc );

AType const a = AType();
QVariant const variant = callbacks[L"name"]( a );
}

int main()
{}

Отказ от ответственности: непроверенный код (за исключением того, что он компилируется с msvc и mingw g ++).

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]