1. ホーム
  2. c++

[解決済み] C++のラムダでキャプチャを関数ポインタとして使用する

2022-10-15 15:36:28

質問

私はC++のラムダとその関数ポインタへの暗黙の変換で遊んでいました。私の最初の例は、ftw関数のコールバックとしてそれらを使用することでした。これは期待どおりに動作します。

#include <ftw.h>
#include <iostream>

using namespace std;

int main()
{
    auto callback = [](const char *fpath, const struct stat *sb,
        int typeflag) -> int {
        cout << fpath << endl;
        return 0;
    };

    int ret = ftw("/etc", callback, 1);

    return ret;
}

キャプチャを使用するように修正した後

int main()
{

    vector<string> entries;

    auto callback = [&](const char *fpath, const struct stat *sb,
        int typeflag) -> int {
        entries.push_back(fpath);
        return 0;
    };

    int ret = ftw("/etc", callback, 1);

    for (auto entry : entries ) {
        cout << entry << endl;
    }

    return ret;
}

コンパイラーエラーが出ました。

error: cannot convert ‘main()::<lambda(const char*, const stat*, int)>’ to ‘__ftw_func_t {aka int (*)(const char*, const stat*, int)}’ for argument ‘2’ to ‘int ftw(const char*, __ftw_func_t, int)’

いくつか読んでみて キャプチャを使ったラムダがあることを知りました。 は暗黙のうちに変換することはできない を関数ポインタに変換することができることを知りました。

これに対する回避策はありますか?暗黙的に変換できないということは、明示的に変換できるということでしょうか?(キャストしてみましたが、うまくいきませんでした)。ラムダを使用して、あるオブジェクトにエントリを追加できるように、作業例を修正するきれいな方法は何でしょうか?

どのように解決するのですか?

キャプチャリングラムダは状態を保持する必要があるため、簡単な回避策はありません。 ではなく ではなく、普通の関数です。関数ポインタのポイントは、単一のグローバルな関数を指していることであり、この情報には状態のための余地がありません。

最も近い回避策(本質的に状態性を破棄する)は、ラムダ/関数からアクセスされるある種のグローバル変数を提供することです。たとえば、伝統的なファンクタオブジェクトを作り、それに静的なメンバ関数を与えて、いくつかのユニークな(グローバル/静的な)インスタンスを参照させることができます。

しかし、それはラムダを捕捉する目的全体を破るようなものです。