SQLite User Forum

How can I send cell and row data to .csv file in a lambda function in C++
Login

How can I send cell and row data to .csv file in a lambda function in C++

(1) By anonymous on 2025-02-18 03:20:03 [source]

I need to use C++ to run a sqlite3 query and send the output of three merged tables to a .csv file. From a Google AI source (at least I think it was an AI source) I found a program with the following lambda function that is included in a sqlite3_exec function call. In this function the cout statements work very nicely to present the data to the screen.
However, when I remove the comments in front of the outPutFile statement and direct the output to the .csv file, get an error that says, … “Variable 'outPutFile' cannot be implicitly captured in a lambda with no capture-default specified” outPutFile is an ofstream object. The Xcode error checker suggests I add &outPutFile between the brackets at the beginning of the lambda function, so it reads [&outPutFile]. However, that causes another error that is, “No matching function for call to 'sqlite3_exec'”.
So, I am at an impasse.
How can I get the outPutFile statement to work or have an alternative that will process the query, cell by cell and row by row so I have control over how it looks in the .csv file.

cout << "Entering sqlite3_exec(...) with lambda function n";

rc = sqlite3_exec(db, sql.c_str(), [](void *data, int argc, char **argv, char **colNames)
{
    std::vector<std::string> rowData;

    for (int i = 0; i < argc; i++) {
        rowData.push_back(argv[i] ? argv[i] : "NULL");
        //outPutFile << rowData[i] << ";";
        cout << rowData[i] << " ";
        if (i == argc-1){cout << endl;}
    }
    static_cast<std::vector<std::vector<std::string>>*>(data)->push_back(rowData);

    return 0;
}, &tableData, &errMsg);

(2) By Igor Tandetnik (itandetnik) on 2025-02-18 04:10:30 in reply to 1 [link] [source]

Well, you could simply output the data to the file in a separate loop, after sqlite3_exec call. You are storing it in tableData, so you could print it from there.

If you insist on writing to the file from the callback, then you need to pass both outPutFile and tableData through data parameter. Something along these lines:

struct Context {
  std::ofstream* pOutputFile;
  std::vector<std::vector<std::string>>* pTableData;
};
Context context{&outPutFile, &tableData};

sqlite3_exec(..., [](void* data, ...) {
  Context* pContext = static_cast<Context*>(data);
  auto& outputFile = *pContext->pOutputFile;
  auto& tableDaata = *pContext->pTableData;
  // The rest of the implementation here; use outputFile and tableData as needed
}, &context, ...);

(3) By Donal Fellows (dkfellows) on 2025-02-18 13:49:12 in reply to 2 [link] [source]

And that's essentially desugaring what the variable-capturing of a lambda does for you. It's just got to be done manually here to get past the API differences.

The Context could also contain a std::function (with the right signature) instead, allowing you to plug the capturing lambda into that.