4

Python/pyqt4 の経験を活用して (Qt4 経由で) C++ を学習していますが、ラムダ式をコンテナーに格納してコールバックとして使用するための適切なイディオムを把握できないようです。

たくさんのフィールドを持つ構造体があります。そして、フィールドを特定の方法で適切にフォーマットできるコールバックのマップを作成したいと考えています。

これが私がやりたいことと同等の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 より前のアプローチがあるかどうかを知りたいです。

次に、ブーストソリューションを見ました。私のプロジェクトはすでにブーストを使用しているので、それが解決策になると思いました。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)));

最後の行を書いた後、自分が車輪を回転させていることに気付きました。ラムダ コールバックのマップ (Qt と互換性があります) を作成するための慣用的なアプローチについて、経験豊富な C++ 開発者に尋ねたほうがよいでしょう。

私の目標は、既知のインデックスと既知の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

1 に答える 1

3

C ++では、ラムダは構文糖衣にすぎず、ファンクター定義をインラインで記述できます。ファンクターは、。を持つオブジェクトoperator()です。したがって、C ++ 11を使用できない場合(古いコンパイラを使用せざるを得ないことが理由の1つですか?)、いつでもファンクタークラスを定義できます。または、これらの概念的なラムダが何もキャプチャしない場合は、単純な古い関数を使用できます。

:-)

ケイ、例を書いてみます。ほんの数分...


ここに行く…

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 ++でコンパイルされることを除く)。

于 2012-11-13T02:29:31.120 に答える