template <typename AT> qsizetype QList::lastIndexOf()

2025-06-06

この関数は、QList 内で指定された要素が最後に現れるインデックスを返します。もし要素が見つからない場合は -1 を返します。

テンプレート関数であること (Being a Template Function)

template <typename AT> の部分は、この関数がテンプレート関数であることを示しています。これはつまり、AT の部分に任意のデータ型(例: int, QString, ユーザー定義のクラスなど)を指定できるということです。QList に格納されている要素の型と同じ型、あるいはそれに変換可能な型を指定して呼び出すことができます。

qsizetype について (About qsizetype)

qsizetype は Qt が提供する型で、通常は qintptr または size_t に対応します。これは、リストのサイズやインデックスを安全に表現するために使用されます。特に、大規模なリストを扱う際にプラットフォーム間の互換性を確保する上で重要です。

引数 (Arguments)

この関数には、通常、検索したい要素の値を引数として渡します。 例: list.lastIndexOf(value);



よくあるエラーとトラブルシューティング (Common Errors and Troubleshooting)

比較演算子 (operator==()) が未定義 (Undefined Comparison Operator)

QList::lastIndexOf() は、リスト内の要素と検索対象の要素が等しいかどうかを比較するために、内部的に要素の型に対する operator==() を使用します。もし、QList に独自のカスタム型を格納していて、その型に operator==() を定義していない場合、コンパイルエラーが発生します。

エラーの例 (Example Error)

error: no match for 'operator==' (operand types are 'const MyCustomClass' and 'const MyCustomClass')

トラブルシューティング (Troubleshooting)

QList に格納しているカスタム型 MyCustomClass に対して、operator==() を定義してください。これは通常、メンバー関数または非メンバー関数として定義できます。

例 (Example)

// MyCustomClass.h
class MyCustomClass {
public:
    int id;
    QString name;

    MyCustomClass(int i, const QString& n) : id(i), name(n) {}

    // operator==() の定義
    bool operator==(const MyCustomClass& other) const {
        return (id == other.id && name == other.name);
    }
};

// main.cpp
#include <QList>
#include <QDebug>
#include "MyCustomClass.h" // 上で定義したクラスをインクルード

int main() {
    QList<MyCustomClass> myList;
    myList.append(MyCustomClass(1, "Alpha"));
    myList.append(MyCustomClass(2, "Beta"));
    myList.append(MyCustomClass(1, "Alpha")); // 同じ値のオブジェクトを再度追加

    MyCustomClass searchItem(1, "Alpha");
    qsizetype index = myList.lastIndexOf(searchItem);
    qDebug() << "Last index of searchItem:" << index; // 出力: 2

    MyCustomClass nonExistentItem(3, "Gamma");
    qsizetype nonExistentIndex = myList.lastIndexOf(nonExistentItem);
    qDebug() << "Last index of nonExistentItem:" << nonExistentIndex; // 出力: -1

    return 0;
}

ポイント
operator==()const 関数として定義することが推奨されます。これは、lastIndexOf() がリストの要素を const 参照として受け取るためです。

ポインタの比較 (Comparing Pointers)

QList<MyClass*> のように、カスタムクラスのポインタQList に格納している場合、lastIndexOf() はポインタのアドレスを比較します。これは、operator==() をカスタムクラス自体に定義していても、期待通りの動作をしない可能性があります。

問題の例 (Example Problem)

#include <QList>
#include <QDebug>

class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
    // この operator==() は、ポインタの比較には使われない
    bool operator==(const MyClass& other) const {
        return value == other.value;
    }
};

int main() {
    QList<MyClass*> myPointerList;
    MyClass* obj1 = new MyClass(10);
    MyClass* obj2 = new MyClass(20);
    MyClass* obj3 = new MyClass(10); // 値は同じだが、別のアドレスのオブジェクト

    myPointerList.append(obj1);
    myPointerList.append(obj2);
    myPointerList.append(obj3);

    // obj1 と obj3 は値が同じだが、アドレスは異なる
    qsizetype index = myPointerList.lastIndexOf(obj1);
    qDebug() << "Last index of obj1:" << index; // 出力: 0 (obj1自身のアドレスが見つかる)

    MyClass searchVal(10); // 値が10のオブジェクトを作成
    // ここで問題が発生する可能性: lastIndexOf() は MyClass* を引数に取るため、
    // searchVal (MyClassオブジェクト) を直接渡すと型が一致しないか、
    // 一時オブジェクトのポインタと比較することになり意図しない結果になる。
    // 仮に searchVal のポインタを渡しても、その一時ポインタとリスト内のポインタは異なる。
    // myPointerList.lastIndexOf(&searchVal); // これは多くの場合 -1 を返す
    // 解決策は後述
    
    delete obj1;
    delete obj2;
    delete obj3;
    return 0;
}

トラブルシューティング (Troubleshooting)

ポインタのリストで値による比較を行いたい場合は、以下のいずれかの方法を検討してください。

  • スマートポインタを使用する
    QSharedPointer<MyClass> などのスマートポインタを使用し、カスタム型の operator==() を定義します。スマートポインタは値のように振る舞うため、QList との相性が良いです。

  • 手動でイテレーションする
    lastIndexOf() の代わりに、リストを逆方向にループして、要素のプロパティを比較します。

    #include <QList>
    #include <QDebug>
    
    class MyClass {
    public:
        int value;
        MyClass(int v) : value(v) {}
    };
    
    int main() {
        QList<MyClass*> myPointerList;
        MyClass* obj1 = new MyClass(10);
        MyClass* obj2 = new MyClass(20);
        MyClass* obj3 = new MyClass(10);
    
        myPointerList.append(obj1);
        myPointerList.append(obj2);
        myPointerList.append(obj3);
    
        int searchValue = 10;
        qsizetype lastIndex = -1;
        for (qsizetype i = myPointerList.size() - 1; i >= 0; --i) {
            if (myPointerList.at(i)->value == searchValue) {
                lastIndex = i;
                break;
            }
        }
        qDebug() << "Last index of value 10 (manual search):" << lastIndex; // 出力: 2
    
        delete obj1;
        delete obj2;
        delete obj3;
        return 0;
    }
    
  • QList<T> を使用する
    可能であれば、ポインタではなくオブジェクトを直接 QList に格納します。これにより、operator==() が適切に呼び出されます。

異なる型での検索 (Searching with Different Types)

QList<int> に対して lastIndexOf(double) のように、リストの要素型と異なる型で検索しようとすると、コンパイラが暗黙の型変換を試みます。これがうまくいかない場合や、意図しない変換が行われる可能性があります。

例 (Example)

#include <QList>
#include <QDebug>

int main() {
    QList<int> intList;
    intList << 1 << 2 << 3 << 2 << 4;

    // intList.lastIndexOf(2.5); // コンパイルエラーまたは意図しない結果
    // 2.5 が int に変換され、lastIndexOf(2) として動作する可能性
    // しかし、このような暗黙の型変換は避けるべき
    
    // 正しい使い方
    qsizetype index = intList.lastIndexOf(2);
    qDebug() << "Last index of 2:" << index; // 出力: 3
    
    return 0;
}

トラブルシューティング (Troubleshooting)

常に QList に格納されている要素の型と一致する、または明確にキャストした値を検索対象として渡してください。

QList の変更とインデックスの無効化 (Modifying QList and Index Invalidation)

QList::lastIndexOf() を呼び出した後、QList の内容を変更(要素の追加、削除、並べ替えなど)すると、以前に取得したインデックスが無効になる可能性があります。

問題の例 (Example Problem)

#include <QList>
#include <QDebug>

int main() {
    QList<QString> myList;
    myList << "A" << "B" << "C" << "B" << "D";

    qsizetype indexB = myList.lastIndexOf("B"); // indexB = 3

    myList.removeAt(0); // "A" を削除。リストがシフトする

    // indexB はもう正しい位置を指していない可能性がある
    // (この例では "B" の位置は 2 になる)
    qDebug() << "Original index of 'B':" << indexB; // 出力: 3
    qDebug() << "Element at original index:" << (indexB < myList.size() ? myList.at(indexB) : "INVALID"); // INVALID または異なる値
    
    qsizetype newIndexB = myList.lastIndexOf("B");
    qDebug() << "New index of 'B':" << newIndexB; // 出力: 2

    return 0;
}

トラブルシューティング (Troubleshooting)

インデックスを使用して後続の操作を行う場合は、QList の内容が変更されていないことを確認してください。もし変更される可能性がある場合は、lastIndexOf() を再呼び出しして最新のインデックスを取得するか、イテレータを使用するなど、より堅牢な方法を検討してください。

大文字・小文字の区別 (Case Sensitivity - QStringList の場合)

QStringListQList<QString> のエイリアス)に対して lastIndexOf() を使用する場合、デフォルトでは大文字・小文字を区別して検索します。

例 (Example)

#include <QStringList>
#include <QDebug>

int main() {
    QStringList myStringList;
    myStringList << "Apple" << "banana" << "Apple" << "orange";

    qsizetype index1 = myStringList.lastIndexOf("apple"); // 大文字・小文字区別あり
    qDebug() << "Last index of 'apple' (case-sensitive):" << index1; // 出力: -1

    qsizetype index2 = myStringList.lastIndexOf("Apple"); // 大文字・小文字区別あり
    qDebug() << "Last index of 'Apple' (case-sensitive):" << index2; // 出力: 2

    return 0;
}

トラブルシューティング (Troubleshooting)

大文字・小文字を区別せずに検索したい場合は、QString::lastIndexOf() のオーバーロードにある Qt::CaseInsensitive オプションを使用します。しかし、QList::lastIndexOf() 自体には直接この引数はありません。そのため、QStringList の場合は、各要素を比較する際に QString::compare()Qt::CaseInsensitive で使用するなど、手動で処理を記述する必要があります。

#include <QStringList>
#include <QDebug>

int main() {
    QStringList myStringList;
    myStringList << "Apple" << "banana" << "Apple" << "orange";

    QString searchString = "apple";
    qsizetype lastIndexInsensitive = -1;
    for (qsizetype i = myStringList.size() - 1; i >= 0; --i) {
        if (myStringList.at(i).compare(searchString, Qt::CaseInsensitive) == 0) {
            lastIndexInsensitive = i;
            break;
        }
    }
    qDebug() << "Last index of 'apple' (case-insensitive):" << lastIndexInsensitive; // 出力: 2

    return 0;
}
  • コンテナの選択を見直す
    大規模なデータや頻繁な検索を行う場合、QList よりも QMapQHash のような他のQtコンテナが適している場合があります。これらのコンテナはキーに基づいて高速な検索を提供します。
  • ドキュメントを確認する
    Qt の公式ドキュメントは非常に詳細です。QList::lastIndexOf() や関連する関数の要件(例えば、operator==() の必要性など)を再確認してください。
  • qDebug() を活用する
    要素の値やインデックスを途中で出力して、期待通りのデータが扱われているか確認します。
  • デバッガを使用する
    QList の内容や lastIndexOf() の戻り値をステップ実行で確認することで、問題の特定に役立ちます。


例1:int 型のリストでの使用 (Using with a list of int)

最も基本的な例です。整数のリストから特定の数値が最後に現れる位置を見つけます。

#include <QList>
#include <QDebug> // デバッグ出力用

int main() {
    // 1. QList<int> の作成と要素の追加
    QList<int> intList;
    intList << 10 << 20 << 30 << 20 << 40 << 10;

    qDebug() << "Original List (int):" << intList; // リストの内容を表示

    // 2. 特定の要素が最後に現れるインデックスを検索
    int searchValue1 = 20;
    qsizetype lastIndex1 = intList.lastIndexOf(searchValue1);
    qDebug() << "Last index of" << searchValue1 << ":" << lastIndex1;
    // 出力: Last index of 20 : 3 (0-indexed: 10[0], 20[1], 30[2], 20[3], 40[4], 10[5])

    int searchValue2 = 10;
    qsizetype lastIndex2 = intList.lastIndexOf(searchValue2);
    qDebug() << "Last index of" << searchValue2 << ":" << lastIndex2;
    // 出力: Last index of 10 : 5

    // 3. リストに存在しない要素を検索
    int searchValue3 = 99;
    qsizetype lastIndex3 = intList.lastIndexOf(searchValue3);
    qDebug() << "Last index of" << searchValue3 << ":" << lastIndex3;
    // 出力: Last index of 99 : -1 (見つからない場合は -1 を返す)

    return 0;
}

解説

  • lastIndexOf(99) は、リストに 99 が存在しないため -1 を返します。
  • lastIndexOf(10) は、10 がリスト内で最後に現れるインデックス 5 を返します。
  • lastIndexOf(20) は、20 がリスト内で最後に現れるインデックス 3 を返します。
  • QList<int> を作成し、複数の整数(重複を含む)を追加しています。

例2:QString 型のリストでの使用 (Using with a list of QString)

文字列のリストで lastIndexOf() を使用する例です。デフォルトでは大文字・小文字を区別します。

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    // 1. QList<QString> の作成と要素の追加
    QList<QString> stringList;
    stringList << "apple" << "banana" << "orange" << "Apple" << "banana" << "grape";

    qDebug() << "Original List (QString):" << stringList;

    // 2. 特定の文字列が最後に現れるインデックスを検索 (大文字・小文字を区別)
    QString searchString1 = "banana";
    qsizetype lastIndex1 = stringList.lastIndexOf(searchString1);
    qDebug() << "Last index of '" << searchString1 << "':" << lastIndex1;
    // 出力: Last index of ' banana ': 4

    QString searchString2 = "apple";
    qsizetype lastIndex2 = stringList.lastIndexOf(searchString2);
    qDebug() << "Last index of '" << searchString2 << "':" << lastIndex2;
    // 出力: Last index of ' apple ': 0 (小文字の "apple" は最初の要素のみ)

    QString searchString3 = "Apple";
    qsizetype lastIndex3 = stringList.lastIndexOf(searchString3);
    qDebug() << "Last index of '" << searchString3 << "':" << lastIndex3;
    // 出力: Last index of ' Apple ': 3 (大文字の "Apple" はインデックス 3 にある)

    // 3. 存在しない文字列を検索
    QString searchString4 = "kiwi";
    qsizetype lastIndex4 = stringList.lastIndexOf(searchString4);
    qDebug() << "Last index of '" << searchString4 << "':" << lastIndex4;
    // 出力: Last index of ' kiwi ': -1

    return 0;
}

解説

  • lastIndexOf() はデフォルトで大文字・小文字を区別します。そのため、"apple" と "Apple" は異なるものとして扱われます。
  • QList<QString> を作成しています。QStringoperator==() を適切に定義しているので、そのまま使用できます。

例3:カスタム型での使用 (Using with a Custom Type)

QList に独自のカスタムクラスのオブジェクトを格納する場合、そのクラスにoperator==() を定義する必要があります。定義しないとコンパイルエラーになります。

#include <QList>
#include <QString>
#include <QDebug>

// カスタムクラスの定義
class Book {
public:
    QString title;
    QString author;
    int year;

    // コンストラクタ
    Book(const QString& t, const QString& a, int y) : title(t), author(a), year(y) {}

    // 重要: QList::lastIndexOf() で比較するために operator==() を定義する
    bool operator==(const Book& other) const {
        // 全てのメンバーが一致する場合に true を返す
        return (title == other.title && author == other.author && year == other.year);
    }
    
    // (オプション) QDebug で表示するための operator<< を定義すると便利
    friend QDebug operator<<(QDebug debug, const Book& book) {
        QDebugStateSaver saver(debug);
        debug.nospace() << "Book(Title:\"" << book.title << "\", Author:\"" << book.author << "\", Year:" << book.year << ")";
        return debug;
    }
};

int main() {
    // 1. QList<Book> の作成と要素の追加
    QList<Book> bookList;
    bookList.append(Book("The Lord of the Rings", "J.R.R. Tolkien", 1954));
    bookList.append(Book("Pride and Prejudice", "Jane Austen", 1813));
    bookList.append(Book("The Hobbit", "J.R.R. Tolkien", 1937));
    bookList.append(Book("The Lord of the Rings", "J.R.R. Tolkien", 1954)); // 複製
    bookList.append(Book("1984", "George Orwell", 1949));

    qDebug() << "Original List (Book):" << bookList;

    // 2. 特定のBookオブジェクトが最後に現れるインデックスを検索
    Book searchBook1("The Lord of the Rings", "J.R.R. Tolkien", 1954);
    qsizetype lastIndex1 = bookList.lastIndexOf(searchBook1);
    qDebug() << "Last index of 'The Lord of the Rings':" << lastIndex1;
    // 出力: Last index of 'The Lord of the Rings': 3 (インデックス 3 に複製が存在)

    Book searchBook2("The Hobbit", "J.R.R. Tolkien", 1937);
    qsizetype lastIndex2 = bookList.lastIndexOf(searchBook2);
    qDebug() << "Last index of 'The Hobbit':" << lastIndex2;
    // 出力: Last index of 'The Hobbit': 2

    // 3. 存在しないBookオブジェクトを検索
    Book searchBook3("Non-existent Book", "Unknown Author", 2000);
    qsizetype lastIndex3 = bookList.lastIndexOf(searchBook3);
    qDebug() << "Last index of 'Non-existent Book':" << lastIndex3;
    // 出力: Last index of 'Non-existent Book': -1

    return 0;
}

解説

  • QDebug 出力用の operator<< を定義すると、デバッグ時にカスタムオブジェクトの内容を簡単に確認できます。
  • 最も重要な点は、Book クラス内で bool operator==(const Book& other) const を定義していることです。これがないと、lastIndexOf()Book オブジェクトを比較する方法がわからないため、コンパイルエラーになります。
  • Book というカスタムクラスを定義し、そのオブジェクトを QList に格納しています。

lastIndexOf() には、検索をリストのどの位置から開始するかを指定できるオーバーロードがあります。これは通常、リストの末尾から逆方向に検索する際の開始点として使用されます。

qsizetype QList::lastIndexOf(const T &value, qsizetype from = -1) const

from のデフォルト値は -1 で、これはリストの最後まで(つまりリスト全体)を検索することを意味します。特定のインデックスから逆方向に検索を開始したい場合に使います。

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<QString> fruits;
    fruits << "apple" << "banana" << "cherry" << "apple" << "banana" << "date";

    qDebug() << "Original List:" << fruits;

    // 1. デフォルト (リスト全体を検索)
    QString searchItem = "banana";
    qsizetype indexDefault = fruits.lastIndexOf(searchItem);
    qDebug() << "Last index of '" << searchItem << "' (default):" << indexDefault;
    // 出力: 4 (インデックス 4 の "banana" が最後)

    // 2. インデックス 3 から逆方向に検索を開始 (fruits[3] は "apple")
    // 検索範囲: fruits[3], fruits[2], fruits[1], fruits[0]
    qsizetype indexFrom3 = fruits.lastIndexOf(searchItem, 3);
    qDebug() << "Last index of '" << searchItem << "' (from index 3):" << indexFrom3;
    // 出力: 1 (fruits[1] の "banana" が見つかる)

    // 3. インデックス 0 から逆方向に検索を開始 (fruits[0] は "apple")
    // 検索範囲: fruits[0] のみ
    qsizetype indexFrom0 = fruits.lastIndexOf(searchItem, 0);
    qDebug() << "Last index of '" << searchItem << "' (from index 0):" << indexFrom0;
    // 出力: -1 (fruits[0] は "apple" であり、その前に "banana" はない)

    // 4. 無効なインデックスから検索を開始 (通常は避けるべき)
    // from がサイズを超えると、リストの最後の要素から始まる
    qsizetype indexFromLarge = fruits.lastIndexOf(searchItem, 100);
    qDebug() << "Last index of '" << searchItem << "' (from index 100):" << indexFromLarge;
    // 出力: 4 (実質的にデフォルトと同じ挙動)

    // from が負の値の場合、デフォルトと同じ挙動
    qsizetype indexFromNegative = fruits.lastIndexOf(searchItem, -5);
    qDebug() << "Last index of '" << searchItem << "' (from index -5):" << indexFromNegative;
    // 出力: 4

    return 0;
}
  • from が無効な負の値の場合も、リスト全体を検索します。
  • from がリストのサイズ以上の場合、lastIndexOf() はリスト全体を検索します(つまり from = -1 と同じ挙動)。
  • from インデックスは** inclusive (含む)** です。つまり、その位置の要素も検索対象に含まれます。
  • fruits.lastIndexOf(searchItem, 3) は、インデックス 3 ("apple") から逆方向に検索を開始します。この検索範囲内で "banana" が最後に見つかるのはインデックス 1 です。


QList::lastIndexOf() の代替方法 (Alternative Methods for QList::lastIndexOf())

逆方向イテレータを使用した手動検索 (Manual Search using Reverse Iterators)

最も直接的な代替方法であり、最も柔軟性があります。QList の要素を逆方向にイテレートし、条件に合う要素が見つかったらそのインデックスを計算します。これにより、単純な等価比較だけでなく、より複雑な条件での検索が可能です。

利点

  • 検索中に他の処理を挟むことができる。
  • 大文字・小文字を区別しない検索など、デフォルトの operator==() 以外の比較方法を指定できる。
  • 任意の複雑な検索条件を定義できる(例: 特定のプロパティが一致するか、特定の範囲内にあるかなど)。

欠点

  • パフォーマンスは lastIndexOf() と同等か、カスタムロジックによっては遅くなる可能性がある。
  • lastIndexOf() に比べてコード量が増える。

コード例

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<QString> fruits;
    fruits << "apple" << "banana" << "cherry" << "Apple" << "banana" << "date";

    qDebug() << "Original List:" << fruits;

    // 例1: 大文字・小文字を区別しない最後の "banana" を検索
    QString searchItemCaseInsensitive = "BANANA";
    qsizetype lastIndexInsensitive = -1;

    // QList の末尾から先頭へ逆方向にイテレート
    // QList::size() - 1 が最後のインデックス
    for (qsizetype i = fruits.size() - 1; i >= 0; --i) {
        // QString::compare() を使用して大文字・小文字を区別しない比較を行う
        if (fruits.at(i).compare(searchItemCaseInsensitive, Qt::CaseInsensitive) == 0) {
            lastIndexInsensitive = i; // 見つかったインデックスを保存
            break; // 最初に見つかった時点でループを終了(これが最後の出現)
        }
    }
    qDebug() << "Last index of '" << searchItemCaseInsensitive << "' (case-insensitive):" << lastIndexInsensitive;
    // 出力: Last index of ' BANANA ' (case-insensitive): 4

    // 例2: 特定の条件(例: 文字列の長さが5以上で、かつ最後に現れるもの)
    qsizetype lastLongStringIndex = -1;
    for (qsizetype i = fruits.size() - 1; i >= 0; --i) {
        if (fruits.at(i).length() >= 5) { // 文字列の長さが5以上
            lastLongStringIndex = i;
            break;
        }
    }
    qDebug() << "Last index of string with length >= 5:" << lastLongStringIndex;
    // 出力: Last index of string with length >= 5: 5 (date)

    return 0;
}

std::find_end() (C++ Standard Library Algorithm)

C++ の標準ライブラリには、指定されたシーケンス内で特定のサブシーケンスまたは要素が最後に現れる位置を見つけるための std::find_end() があります。これは要素の単一検索には直接的ではありませんが、より複雑な検索パターンで役立つ可能性があります。ただし、QList の要素型が標準のイテレータと互換性がある必要があります(Qtのコンテナは通常互換性があります)。

利点

  • 汎用性が高い。
  • 標準ライブラリのアルゴリズムを使用するため、慣れている開発者には分かりやすい。

欠点

  • QList のネイティブなメソッドではない。
  • カスタム型の場合、operator==() の定義が必要。
  • QList::lastIndexOf() ほど直接的ではない。

コード例 (注意: std::find_end はシーケンスの検索によく使われるが、単一要素の最後の出現には std::find を逆イテレータと組み合わせる方が一般的)

ここでは、単一要素の最後の出現を std::find と逆イテレータで実現する方法を示します。

#include <QList>
#include <QString>
#include <QDebug>
#include <algorithm> // std::find 用

int main() {
    QList<QString> fruits;
    fruits << "apple" << "banana" << "cherry" << "apple" << "banana" << "date";

    qDebug() << "Original List:" << fruits;

    QString searchItem = "banana";

    // 逆方向イテレータを使用: rbegin() から rend() まで
    // std::find は最初に見つかったイテレータを返すので、逆方向で検索すれば最後の出現になる
    auto it = std::find(fruits.rbegin(), fruits.rend(), searchItem);

    qsizetype lastIndex = -1;
    if (it != fruits.rend()) {
        // 逆方向イテレータから通常のインデックスを計算する
        // (rend() - 1) は最後の要素、(rbegin()) は最初の要素
        // 実際には、std::distance で rend() から見つかった位置までの距離を計算し、
        // その距離を QList のサイズから引くことでインデックスが得られる
        lastIndex = std::distance(it, fruits.rend()) - 1;
    }
    qDebug() << "Last index of '" << searchItem << "' (using std::find + rbegin/rend):" << lastIndex;
    // 出力: Last index of ' banana ': 4

    return 0;
}

解説

  • インデックスの計算は少し複雑です。std::distance(it, fruits.rend()) は、見つかったイテレータから rend() までの距離(要素数)を返します。この値から 1 を引くことで、通常のインデックスが得られます。
  • std::find() は与えられた範囲で最初に見つかった要素のイテレータを返します。逆方向で検索しているため、これが通常の順序での最後の出現となります。
  • QList::rbegin()QList::rend() は、それぞれリストの末尾から先頭に向かう逆方向イテレータを返します。

std::find_if() とラムダ式 (C++ Standard Library Algorithm with Lambda)

std::find_if() は、特定の条件を満たす要素を検索するための汎用アルゴリズムです。ラムダ式と組み合わせることで、非常に柔軟な検索ロジックをインラインで記述できます。これも逆方向イテレータと組み合わせて最後の出現を検索します。

利点

  • 標準ライブラリの強力な機能を利用できる。
  • コードが簡潔になる(特にラムダ式を使用する場合)。
  • 非常に柔軟で、任意の検索ロジックを適用できる。

欠点

  • QList のネイティブなメソッドではない。
  • インデックスの計算が手動検索と同様に必要。

コード例

#include <QList>
#include <QString>
#include <QDebug>
#include <algorithm> // std::find_if 用

int main() {
    QList<QString> products;
    products << "Laptop A" << "Mouse" << "Keyboard" << "Laptop B" << "Monitor";

    qDebug() << "Original List:" << products;

    // 例: "Laptop" を含む文字列が最後に現れるインデックスを検索 (大文字・小文字を区別しない)
    QString searchKeyword = "laptop";
    qsizetype lastLaptopIndex = -1;

    auto it = std::find_if(products.rbegin(), products.rend(),
                           [&](const QString& item) {
                               // item が searchKeyword を大文字・小文字を区別せずに含むか
                               return item.contains(searchKeyword, Qt::CaseInsensitive);
                           });

    if (it != products.rend()) {
        lastLaptopIndex = std::distance(it, products.rend()) - 1;
    }
    qDebug() << "Last index of item containing '" << searchKeyword << "':" << lastLaptopIndex;
    // 出力: Last index of item containing ' laptop ': 3 (Laptop B)

    return 0;
}

解説

  • std::distance を使用してインデックスを計算する部分は、std::find() の例と同じです。
  • contains() メソッドと Qt::CaseInsensitive オプションを使用して、大文字・小文字を区別しない部分文字列検索を行っています。
  • ラムダ式 [&](const QString& item) { return item.contains(searchKeyword, Qt::CaseInsensitive); } は、各要素に対して評価される述語(条件)を定義します。

QListIterator (Qt Iterators)

QList には、よりC++スタイルなイテレータを提供する QListIterator があります。これは順方向イテレータですが、手動検索の文脈で触れておきます。lastIndexOf() の代替としては、逆方向イテレータやインデックスベースのループの方が直接的です。

  • リストにカスタムオブジェクトのポインタが格納されている場合

    • lastIndexOf() はポインタアドレスを比較するため、手動ループまたはスマートポインタの使用を検討してください。
  • パフォーマンスが非常に重要で、カスタムの比較ロジックを最適化したい場合

    • 手動ループが最も制御しやすく、必要に応じて最適化を施すことができます。
  • operator==() 以外の複雑な条件で最後の出現を検索する場合、または大文字・小文字を区別しない検索が必要な場合

    • 逆方向ループと手動での条件チェック (for (qsizetype i = ...; i >= 0; --i)) が最も理解しやすく、Qt に慣れている開発者には自然です。
    • std::find_if() と逆方向イテレータを組み合わせる方法も強力ですが、C++の標準アルゴリズムに慣れている必要があります。
    • QList::lastIndexOf() が最も簡潔で推奨されます。