【问题标题】:C++ pass list of function calls as parametersC++ 将函数调用列表作为参数传递
【发布时间】:2020-08-25 07:49:20
【问题描述】:

我目前正在使用 C++11 在 Qt 中设置一个单元测试帮助程序类,它可以验证在测试期间发出的信号与其顺序无关,例如:

void TestUtils::verifyVolumeAdjustment(const QSignalSpy &vol_spy, uint percent)
{
    for(QList<QVariant> vol_call_args : vol_spy){
        if(vol_call_args.at(0).toInt() == percent)
        {
            return;
        }
    }
    QString err = QString("volume never set to %1").arg(QString::number(percent));
    QFAIL(err.toLocal8Bit().constData());
}

我有很多这样的功能,所有这些功能都用于检查是否发出了某些信号。现在我需要编写顺序很重要的测试。在这些测试中,我需要验证例如:

Volume set to 10
Volume set to 50

但完全按照这个顺序。现在我的问题是,是否有一种方法可以使用可变参数模板或类似的方法将函数调用列表传递给函数。我想通用订单检查功能是这样的:

void checkExecutionOrder(const QSignalSpy& spy, FunctionCallList call_list){
    
    for(int i = 0; i < call_list.length(), i++){
         QSignalSpy temp;
         temp.append(spy.at(i)); //create a temporary copy of that caught signal to ensure its the only thing validated
         call_list[i].call(temp, arguments); // call the function from the list with modified spy and remaining arguments
    }
}

有没有什么好的方法可以让我不必为每个函数创建一个顺序敏感的测试函数?

【问题讨论】:

  • 为什么不让它更简单呢?例如。传递的不是一个单一的百分比值,而是一个列表,例如:verifyVolumeAdjustment(const QSignalSpy &amp;vol_spy, const QList&lt;uint&gt; &amp;percents)。在正文中,您检查信号的参数是否与列表中的百分比相对应。

标签: c++ function qt templates variadic-templates


【解决方案1】:

另一种选择是使用 lambdas.. 方法如下:

  1. 定义获取列表的方法,向量为std::functions
  2. 在方法内部执行一个 for 循环并调用每个函数
  3. 要调用该方法,请传递一个填充有要调用的 lambdas 的向量...

void myFooFunction(QVector<std::function<int(int)>>& myVec)
{
    for(auto& x:myVec)
    {
        x(1);
    }
}

int main(int argc, char* argv[])
{

    QVector<std::function<int(int)>> x;
    auto f1 = [](int x){qDebug() << "x ++" << x; return x++;};
    auto f2 = [](int x){qDebug() << "x --" << x; return x--;};
    x.push_back(f1);
    x.push_back(f2);
    myFooFunction(x);

【讨论】:

  • 不明白,但这并不能解决我需要为我要检查的每件事编写一个专用函数的问题,因为有些函数需要一个整数,两个整数,有时还有很多其他的东西。
  • nop...如果您已经定义了向量中的方法,只需将它们推回...
【解决方案2】:

您可以使用std::vectorstd::function 将具有相同签名的函数列表传递给checkExecutionOrder

#include <vector>
#include <functional>

using FunctionCall = std::function< void(int,int) >;
using FunctionCallList = std::vector<FunctionCall>;

void checkExecutionOrder(FunctionCallList call_list){

    for (auto f : call_list) {    
         f(42,42);
    }
}

void foo(int x,int y){}

int main() {
    checkExecutionOrder( { foo,foo } );
}

【讨论】: