繁体   English   中英

在 C++ 中,是否可以定义一个具有可变代码块的函数,以执行并通过另一个函数传递?

[英]In C++, is it possible to define a function with a varying code block to be executed and passed via another function?

我有一个处理 SQL 查询的类(它使用 Qt 函数,但我认为这无关紧要)。 所有写入数据的查询都具有完全相同的基本框架,如下所示:

bool Database::someSqlFunction(some variables)
{
    if (! startTransaction()) {
        return false;
    }

    QSqlQuery query(m_db);

    try {
        ... Code using the passed variables and query ...
        commitTransaction();
    } catch (...) {
        rollbackTransaction(query);
        return false;
    }

    return true;
}

是否可以重用此代码,以便不必为每个函数定义它? 我想过使用一个函数来调用,该函数带有指向包含不同代码的函数的指针,但是每个函数的签名都不同,因此我必须为每种情况定义一个重载的函数; 我也考虑过使用预处理器来生成函数,但是对于不同数量和类型的参数,这是同样的问题。

可以将要执行的代码块传递给另一个函数吗? 或者这可以通过功能模板来完成吗?

编辑:这是如何实现的:

在标题中:

template<typename SqlFunction>
bool writeHelper(SqlFunction sqlFunction)
{
    if (! startTransaction()) {
        return false;
    }

    QSqlQuery query(m_db);

    try {
        sqlFunction(query);
        commitTransaction();
    } catch (...) {
        rollbackTransaction(query);
        return false;
    }

    return true;
}

和使用它的示例函数:

bool Database::registerPlayers(const QString &name, int markerId)
{
    return writeHelper([&](QSqlQuery &query) {
        queryPrepare(query, QStringLiteral("INSERT INTO players(id, name, marker) "
                                           "VALUES(NULL, ?, ?)"));
        query.bindValue(0, name);
        query.bindValue(1, markerId != 0 ? markerId : SQLITE_NULL);
        queryExec(query);
    });
}

编辑2:没有模板也可以实现相同的效果:

使用std::function ,可以简单地传递实际函数中定义的 lambda,而无需使用模板。 辅助函数的实现如下所示:

bool Database::writeHelper(std::function<void(QSqlQuery &query)> sqlFunction)
{
    if (! startTransaction()) {
        return false;
    }

    QSqlQuery query(m_db);
    try {
        sqlFunction(query);
        commitTransaction();
    } catch (...) {
        rollbackTransaction(query);
        return false;
    }

    return true;
}

无论如何,使用模板方法显然更好,因为在这种情况下,编译器将生成所需的函数构建时间并可以优化,而他不知道使用 std::function 方法实际会做什么,因为调用发生在运行时。

Lambda 闭包似乎正是您所需要的。
https://en.cppreference.com/w/cpp/language/lambda

例如,通用算法与您的用例非常相似:一个不会改变的通用算法和一些可以在调用时免费提供的小部分。
https://en.cppreference.com/w/cpp/header/algorithm

在不知道预期的确切细节的情况下,我在这里提供了一个简单的例子:

#include <iostream>

template<typename Fnct>
void
common_part(Fnct fnct)
{
  std::cout << "begin common part\n";
  for(auto i=0; i<3; ++i)
  {
    std::cout << "iteration " << i << " of common part\n";
    fnct(i);
  }
  std::cout << "end common part\n";
}

void
specific_function_A()
{
  common_part(
    [&](const auto &n)
    {
      std::cout << "specific part A: " << n << '\n';
    });
}

void
specific_function_B(int something_else)
{
  common_part(
    [&](const auto &n)
    {
      std::cout << "specific part B: " << n+something_else << '\n';
      something_else*=2;
    });
}

int
main()
{
  specific_function_A();
  std::cout << "~~~~~~~~\n";
  specific_function_B(100);
  return 0;
}

即使 lambda 闭包的签名始终相同,也可以将捕获视为提供附加参数的解决方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM