vendredi 14 juillet 2023

std::function does not match lambda as parameter in fold-expression template function

in c++ 11 I declared 2 functions in the same namespace (class Database):

template <typename... Ts> bool HandleStmt(sqlite3_stmt *pSQL, std::function<void(std::tuple<Ts...>)> f)
bool Database::WALModeEnabled()

I get this error when compiling:

source/Database.cpp: In member function 'bool Database::WALModeEnabled()':
source/Database.cpp:180:30: error: no matching function for call to 
'Database::HandleStmt(sqlite3_stmt*&, Database::WALModeEnabled()::<lambda(std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >)>&)'
  180 |         HandleStmt(pSQL, func);
      |                              ^
In file included from source/Database.cpp:6:
source/include/Database.h:151:36: note: candidate: 'template<class ... Ts> bool Database::HandleStmt(sqlite3_stmt*, std::function<void(std::tuple<_Tps ...>)>)'
  151 |     template <typename... Ts> bool HandleStmt(sqlite3_stmt *pSQL, std::function<void(std::tuple<Ts...>)> f)
      |                                    ^~~~~~~~~~
source/include/Database.h:151:36: note:   template argument deduction/substitution failed:
source/Database.cpp:180:30: note:   'Database::WALModeEnabled()::<lambda(std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >)>' is not derived from 'std::function<void(std::tuple<_Tps ...>)>'
  180 |         HandleStmt(pSQL, func);
      |                              ^

WALModeEnabled prepares an SQL statement and calls the HandleStmt with the stmt pointer and a lambda containing some code that is executed when the SQL stmt is done/found, implemented in Database.cpp:

bool Database::WALModeEnabled()
{
    sqlite3_stmt *pSQL = nullptr;
    bool WALMode = false;
    if (PrepareStmt(&pSQL, "PRAGMA journal_mode")) {
        auto func = [&WALMode](std::tuple<std::string> wal_from_db) {
            WALMode = (std::get<0>(wal_from_db) == "WAL");
        };
        HandleStmt(pSQL, func);
    }

    CleanStmt(pSQL);
    return WALMode;
}

HandleStmt wraps sql stmt with SQLITE_BUSY handling in a generic function: This function is implemented where it is declared in the Database class, Database.h.

template <typename... Ts> bool HandleStmt(sqlite3_stmt *pSQL, std::function<void(std::tuple<Ts...>)> f)
{
    bool hasData = true;
    while (hasData) {
        switch (sqlite3_step(pSQL)) {
            case SQLITE_ROW:
                f(selectstmt::make_result<Ts...>(pSQL));
                break;
            case SQLITE_BUSY:
                sqlite3_sleep(SQL_BUSY_TIMEOUT_MS);
                break;
            case SQLITE_DONE:
            case SQLITE_OK:
                hasData = false;
                break;
            default:
                LogError();
                return false;
        }
    }
    return true;
}

The selectstmt::make_result<Ts...>(pSQL) call calls the sqlite3_column_... functions for any number of types, this works and is used in other parts of the code base.


I have tried some thing, all resulting in the code you see above, unable to defeat the error.

Compiler explorer is able to compile it without issue on mvsc x86; but not on clang x86-64 (same error).

Passing a simple test function void test(std::tuple<std::string> wal_from_db) with empty body also results in the same error.

I expect the HandleStmt to be called with a lambda with any number and types of parameters.

Aucun commentaire:

Enregistrer un commentaire