コンカレント・マップとマップ・リデュース

QtConcurrent::map()、QtConcurrent::mapped()、QtConcurrent::mappedReduced() 関数は、QList のようなシーケンス内のアイテムに対して並列に計算を実行します。 QtConcurrent::map() はシーケンスをインプレースで変更し、QtConcurrent::mapped() は変更された内容を含む新しいシーケンスを返し、QtConcurrent::mappedReduced() は単一の結果を返します。

これらの関数は Qt Concurrentフレームワークの一部です。

上記の各関数には、QFuture の代わりに最終結果を返すブロッキング型があります。 これらは非同期型と同じように使用します。

QList<QImage> images = ...;

// Each call blocks until the entire operation is finished.
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);

QtConcurrent::blockingMap(images, scale);

QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

上記の結果型はQFuture オブジェクトではなく、実際の結果型(この場合、QList<QImage>とQImage)であることに注意してください。

同時マップ

QtConcurrent::mapped() は、入力シーケンスとマップ関数を受け取ります。このマップ関数はシーケンスの各項目に対して呼び出され、マップ関数の戻り値を含む新しいシーケンスが返されます。

マップ関数は

U function(const T &t);

T と U はどのような型でも構いませんが(同じ型でも構いません)、T はシーケンスに格納されている型と一致しなければなりません。この関数は,変更された,あるいはマップされた内容を返します.

この例では、シーケンス内のすべての項目にスケール関数を適用する方法を示します:

QImage scaled(const QImage &image)
{
    return image.scaled(100, 100);
}

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);

マップの結果は、QFuture から利用できます。アプリケーションでQFuture を使用する方法の詳細については、QFuture およびQFutureWatcher のドキュメントを参照してください。

インプレースでシーケンスを変更したい場合は、QtConcurrent::map() を使用してください。その場合、map関数は以下の形式でなければなりません:

U function(T &t);

map 関数の戻り値と戻り型は使用されないことに注意してください。

QtConcurrent::map() の使用は、QtConcurrent::mapped() の使用と似ています:

void scale(QImage &image)
{
    image = image.scaled(100, 100);
}

QList<QImage> images = ...;
QFuture<void> future = QtConcurrent::map(images, scale);

シーケンスはその場で変更されるので、QtConcurrent::map() はQFuture を介して結果を返しません。ただし、QFutureQFutureWatcher を使用して、マップの状態を監視することはできます。

並行マップ・リデュース

QtConcurrent::mappedReduced() は QtConcurrent::mapped() と似ていますが、新しい結果を含むシーケンスを返す代わりに、reduce 関数を使用して結果を 1 つの値にまとめます。

reduce 関数は以下の形式でなければなりません:

V function(T &result, const U &intermediate)

T は最終結果の型、U はマップ関数の戻り値の型です。リデュース関数の戻り値と戻り値の型は使用されないことに注意してください。

次のように QtConcurrent::mappedReduced() を呼び出します:

void addToCollage(QImage &collage, const QImage &thumbnail)
{
    QPainter p(&collage);
    static QPoint offset = QPoint(0, 0);
    p.drawImage(offset, thumbnail);
    offset += ...;
}

QList<QImage> images = ...;
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);

reduce 関数は、map 関数によって返された結果ごとに 1 回呼び出され、中間値を結果変数にマージします。QtConcurrent::mappedReduced() は、一度に reduce を呼び出すスレッドが 1 つだけであることを保証しているので、結果変数をロックするためにミューテックスを使用する必要はありません。QtConcurrent::ReduceOptions 列挙型は、リダクションの実行順序を制御する方法を提供します。QtConcurrent::UnorderedReduce (デフォルト) を使用すると、リダクションの順序は未定義になります。QtConcurrent::OrderedReduce を使用すると、リダクションは元のシーケンスの順序で行われます。

その他のAPI機能

シーケンスの代わりにイテレータを使用する

上記の各関数には、シーケンスの代わりにイテレータを受け取るバリアントがあります。シーケンスのバリアントと同じように使用します:

QList<QImage> images = ...;

QFuture<QImage> thumbnails = QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);

// Map in-place only works on non-const iterators.
QFuture<void> future = QtConcurrent::map(images.begin(), images.end(), scale);

QFuture<QImage> collage = QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);

ブロックバリアント

上記の各関数には、QFuture の代わりに最終結果を返すブロッキングバリアントがあります。 非同期バリアントと同じように使います。

QList<QImage> images = ...;

// Each call blocks until the entire operation is finished.
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);

QtConcurrent::blockingMap(images, scale);

QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

上記の結果型はQFuture オブジェクトではなく、実際の結果型(この場合、QList<QImage>とQImage)であることに注意してください。

メンバ関数の使用

QtConcurrent::map()、QtConcurrent::mapped()、および QtConcurrent::mappedReduced() は、メンバ関数へのポインタを受け付けます。メンバ関数のクラス型は、シーケンスに格納されている型と一致しなければなりません:

// QtConcurrent::mappedReduced() は、メンバ関数へのポインタを受け付けますQStringListstrings= ...QFuture<void>squeezedStrings=QtConcurrent::map(strings, &QString::squeeze);// 画像リストの全ピクセルの rgb 値を入れ替える。QList<QImage>images= ...QFuture<QImage>bgrImages=::mapped(images, static) QtConcurrent::mapped(images,static_cast<QImage(QImage::*)()const&>(&QImage::rgbSwapped));// リスト内の全ての文字列の長さの集合を作成します。QStringListstrings= ...QFuture<QSet<int>>wordLengths=QtConcurrent::mappedReduced(strings, &)QString::length                                                             qOverload<const int&>(&QSet<int>::insert));

qOverloadこれは、複数のオーバーロードを持つメソッドの曖昧さを解消するために必要である。

また、QtConcurrent::mappedReduced() を使用する場合、通常の関数とメンバ関数を自由に混在させることができることに注意してください:

// QtConcurrent::mappedReduced() を使用すると、通常の関数とメンバ関数を自由に混在させることができますQStringListstrings= ...QFuture<int>averageWordLength=QtConcurrent::mappedReduced(strings, &)QString::length,computeAverage);// リスト内の全画像の色分布の集合を作る.QList<QImage>images= ...QFuture<QSet<int>>totalColorDistribution= .... QtConcurrent::mappedReduced(images,colorDistribution                                                                        qOverload<const int&>(&QSet<int>::insert));

関数オブジェクトの使用

QtConcurrent::map()、QtConcurrent::mapped()、QtConcurrent::mappedReduced() は、マップ関数用の関数オブジェクトを受け付けます。これらの関数オブジェクトは、関数呼び出しに状態を追加するために使用できます:

struct Scaled
{
    Scaled(int size)
    : m_size(size) { }

    typedef QImage result_type;

    QImage operator()(const QImage &image)
    {
        return image.scaled(m_size, m_size);
    }

    int m_size;
};

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, Scaled(100));

関数オブジェクトはreduce関数でもサポートされています:

struct ImageTransform
{
    void operator()(QImage &result, const QImage &value);
};

QFuture<QImage> thumbNails =
        QtConcurrent::mappedReduced(images, Scaled(100), ImageTransform(),
                                    QtConcurrent::SequentialReduce);

ラムダ式の使用

QtConcurrent::map()、QtConcurrent::mapped()、QtConcurrent::mappedReduced() は、map 関数と reduce 関数にラムダ式を使用できます:

QList<int> vector { 1, 2, 3, 4 };
QtConcurrent::blockingMap(vector, [](int &x) { x *= 2; });

int size = 100;
QList<QImage> images = ...;

QList<QImage> thumbnails = QtConcurrent::mapped(images,
        [&size](const QImage &image) {
            return image.scaled(size, size);
        }
    ).results();

QtConcurrent::mappedReduced() や QtConcurrent::blockingMappedReduced() を使用する場合、通常の関数、メンバ関数、ラムダ式を自由に混在させることができます。

QList<QImage> collage = QtConcurrent::mappedReduced(images,
        [&size](const QImage &image) {
            return image.scaled(size, size);
        },
        addToCollage
   ).results();

ラムダをリデュースオブジェクトとして渡すこともできます:

QList<QImage> collage = QtConcurrent::mappedReduced(images,
        [&size](const QImage &image) {
            return image.scaled(size, size);
        },
        [](QImage &result, const QImage &value) {
            // do some transformation
        }
   ).results();

複数の引数をとる関数のラップ

複数の引数をとる map 関数を使いたい場合は、ラムダ関数やstd::bind() を使って、引数をひとつだけとる関数に変換することができます。

例として、QImage::scaledToWidth() を使ってみましょう:

QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;

scaledToWidth は 3 つの引数("this" ポインタを含む)を取りますが、QtConcurrent::mapped() は引数を 1 つ取る関数を想定しているため、QtConcurrent::mapped() で直接使用することはできません。QtConcurrent::mapped() で QImage::scaledToWidth() を使用するには、幅と 変換モードの値を指定する必要があります:

QList<QImage> images = ...;
std::function<QImage(const QImage &)> scale = [](const QImage &img) {
    return img.scaledToWidth(100, Qt::SmoothTransformation);
};
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scale);

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.