並行フィルタとフィルタ削減

QtConcurrent::filter()、QtConcurrent::filtered()、QtConcurrent::filteredReduced() 関数は、QList のようなシーケンス内の項目を並列にフィルタリングします。QtConcurrent::filter() はシーケンスをインプレースで変更し、 QtConcurrent::filtered() はフィルタリングされた内容を含む新しいシーケンスを返し、 QtConcurrent::filteredReduced() は単一の結果を返します。

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

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

QStringList strings = ...;

// each call blocks until the entire operation is finished
QStringList lowerCaseStrings = QtConcurrent::blockingFiltered(strings, allLowerCase);

QtConcurrent::blockingFilter(strings, allLowerCase);

QSet<QString> dictionary = QtConcurrent::blockingFilteredReduced(strings, allLowerCase, addToDictionary);

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

並行フィルタ

QtConcurrent::filtered() は、入力シーケンスとフィルター関数を受け取ります。このフィルタ関数は、シーケンスの各項目に対して呼び出され、フィルタリングされた値を含む新しいシーケンスが返されます。

フィルタ関数は以下の形式でなければならない:

bool function(const T &t);

T はシーケンスに格納されている型と一致しなければならない。この関数は、その項目を保持する場合はtrue を返し、破棄する場合は false を返します。

この例では、すべて小文字の文字列をQStringList から除外する方法を示している:

bool allLowerCase(const QString &string)
{
    return string.lowered() == string;
}

QStringList strings = ...;
QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings, allLowerCase);

フィルタの結果は、QFuture 。アプリケーションでQFuture を使用する方法については、QFutureQFutureWatcher のドキュメントを参照してください。

シーケンスをその場で変更したい場合は、QtConcurrent::filter() を使用してください:

QStringList strings = ...;
QFuture<void> future = QtConcurrent::filter(strings, allLowerCase);

シーケンスはその場で変更されるため、QtConcurrent::filter() はQFuture 経由では結果を返しません。しかし、QFutureQFutureWatcher を使用して、フィルタの状態を監視することができます。

並行フィルタ-削減

QtConcurrent::filteredReduced() は、QtConcurrent::filtered() と似ていますが、フィルタリングされた結果のシーケンスを返す代わりに、reduce 関数を使用して結果を 1 つの値にまとめます。

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

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

T は最終結果の型、U はフィルタリングされる項目の型です。reduce 関数の戻り値と戻り値の型は使用されないことに注意してください。

このように QtConcurrent::filteredReduced() を呼び出します:

void addToDictionary(QSet<QString> &dictionary, const QString &string)
{
    dictionary.insert(string);
}

QStringList strings = ...;
QFuture<QSet<QString>> dictionary = QtConcurrent::filteredReduced(strings, allLowerCase, addToDictionary);

reduce 関数は、フィルタ関数によって保持された各結果に対して 1 回呼び出され、中間値を結果変数にマージします。QtConcurrent::filteredReduced() は、一度に reduce を呼び出すスレッドが 1 つだけであることを保証しているので、結果変数をロックするためにミューテックスを使用する必要はありません。QtConcurrent::ReduceOptions enum は、リダクションの実行順序を制御する方法を提供します。

その他の API 機能

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

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

QStringList strings = ...;
QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings.constBegin(), strings.constEnd(), allLowerCase);

// filter in-place only works on non-const iterators
QFuture<void> future = QtConcurrent::filter(strings.begin(), strings.end(), allLowerCase);

QFuture<QSet<QString>> dictionary = QtConcurrent::filteredReduced(strings.constBegin(), strings.constEnd(), allLowerCase, addToDictionary);

メンバ関数の使用

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

// keep only images with an alpha channel
QList<QImage> images = ...;
QFuture<void> alphaImages = QtConcurrent::filter(images, &QImage::hasAlphaChannel);

// retrieve gray scale images
QList<QImage> images = ...;
QFuture<QImage> grayscaleImages = QtConcurrent::filtered(images, &QImage::isGrayscale);

// create a set of all printable characters
QList<QChar> characters = ...;
QFuture<QSet<QChar>> set = QtConcurrent::filteredReduced(characters, qOverload<>(&QChar::isPrint),
                                                         qOverload<const QChar&>(&QSet<QChar>::insert));

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

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

// can mix normal functions and member functions with QtConcurrent::filteredReduced()

// create a dictionary of all lower cased strings
extern bool allLowerCase(const QString &string);
QStringList strings = ...;
QFuture<QSet<QString>> lowerCase = QtConcurrent::filteredReduced(strings, allLowerCase,
                                                                 qOverload<const QString&>(&QSet<QString>::insert));

// create a collage of all gray scale images
extern void addToCollage(QImage &collage, const QImage &grayscaleImage);
QList<QImage> images = ...;
QFuture<QImage> collage = QtConcurrent::filteredReduced(images, &QImage::isGrayscale, addToCollage);

関数オブジェクトの使用

QtConcurrent::filter(), QtConcurrent::filtered(), QtConcurrent::filteredReduced() は、フィルタ関数に関数オブジェクトを使用できます。これらの関数オブジェクトは、関数呼び出しに状態を追加するために使用できます:

struct StartsWith
{
    StartsWith(const QString &string)
    : m_string(string) { }

    bool operator()(const QString &testString)
    {
        return testString.startsWith(m_string);
    }

    QString m_string;
};

QList<QString> strings = ...;
QFuture<QString> fooString = QtConcurrent::filtered(strings, StartsWith(QLatin1String("Foo")));

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

struct StringTransform
{
    void operator()(QString &result, const QString &value);
};

QFuture<QString> fooString =
        QtConcurrent::filteredReduced(strings, StartsWith(QLatin1String("Foo")), StringTransform());

ラムダ式の使用

QtConcurrent::filter()、QtConcurrent::filtered()、QtConcurrent::filteredReduced() は、filter 関数と reduce 関数にラムダ式を使用できます:

// keep only even integers
QList<int> list { 1, 2, 3, 4 };
QtConcurrent::blockingFilter(list, [](int n) { return (n & 1) == 0; });

// retrieve only even integers
QList<int> list2 { 1, 2, 3, 4 };
QFuture<int> future = QtConcurrent::filtered(list2, [](int x) {
    return (x & 1) == 0;
});
QList<int> results = future.results();

// add up all even integers
QList<int> list3 { 1, 2, 3, 4 };
QFuture<int> sum = QtConcurrent::filteredReduced(list3,
    [](int x) {
        return (x & 1) == 0;
    },
    [](int &sum, int x) {
        sum += x;
    }
);

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

void intSumReduce(int &sum, int x)
{
    sum += x;
}

QList<int> list { 1, 2, 3, 4 };
QFuture<int> sum = QtConcurrent::filteredReduced(list,
    [] (int x) {
        return (x & 1) == 0;
    },
    intSumReduce
);

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

bool keepEvenIntegers(int x)
{
    return (x & 1) == 0;
}

QList<int> list { 1, 2, 3, 4 };
QFuture<int> sum = QtConcurrent::filteredReduced(list,
    keepEvenIntegers,
    [](int &sum, int x) {
        sum += x;
    }
);

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

複数の引数を取るフィルター関数を使いたい場合は、ラムダ関数やstd::bind() を使って、1つの引数を取る関数に変換することができます。

例として、QString::contains ()を使う:

bool QString::contains(const QRegularExpression &regexp) const;

QString::contains(なぜなら、QtConcurrent::filtered() は 1 つの引数を取る関数を想定しているからです。QtConcurrent::filtered() でQString::contains() を使用するには、正規表現引数の値を指定する必要があります:

QStringList strings = ...;
QFuture<QString> future = QtConcurrent::filtered(list, [](const QString &str) {
    return str.contains(QRegularExpression("^\\S+$")); // matches strings without whitespace
});

ここに含まれる文書の著作権は、それぞれの所有者に帰属します 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。