具有任意数量参数的模板函数

时间:2018-09-13 15:16:44

标签: c++ templates perfect-forwarding

我想编写一个函数invoke_measure_time,它将测量作为参数给出的任何其他函数的执行时间。我部分解决了我的问题,我有以下代码:

int sum(int a, int b){
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    return a + b;
}

template<typename T>
std::pair<std::chrono::milliseconds, T> invoke_measure_time(std::function<T()> f){
    auto start = std::chrono::system_clock::now();
    auto f_result = f();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start);

    return std::make_pair(duration, f_result);
}

int main(){
    auto fun = std::bind(sum, 10, 20);
    auto emma = invoke_measure_time<int>(fun);
    std::cout << "time: " << emma.first.count() << ", result = " << emma.second << std::endl;
}

工作正常,结果如预期,但是main的第一行让我头疼。如何修改invoke_measure_time以接受任何函数,不仅是不带参数的函数?我希望我的主体看起来像这样:

int main(){
    auto emma = invoke_measure_time<int, int, int>(sum, 10, 20);
    std::cout << "time: " << emma.first.count() << ", result = " << emma.second << std::endl;
}

或类似的东西。我该如何实现?

3 个答案:

答案 0 :(得分:4)

如果您改为将temaplte类型更改为通用类型,那么我们可以添加可变参数模板参数以获取该函数的参数。

template<typename Function, typename... Args>
auto invoke_measure_time(Function f, Args&&... args) {
    auto start = std::chrono::system_clock::now();
    auto f_result = f(std::forward<Args>(args)...);
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start);

    return std::make_pair(duration, f_result);
}

采用类似type的任何函数,并将您传递给invoke_measure_time的参数转发给它。它还具有能够像这样调用它的优点

int main(){
    auto emma = invoke_measure_time(sum, 10, 20);
    std::cout << "time: " << emma.first.count() << ", result = " << emma.second << std::endl;
}

答案 1 :(得分:2)

简单的解决方案是使invoke_measure_time接受任何无需参数即可调用的函数对象(为简洁起见,我省略了计时内容):

template <typename F>
auto invoke_and_measure(F f) -> decltype(f()) {
    return f();
}

然后是带有任意参数的任何函数,例如您的sum

int sum(int a,int b) { return a+b; }

可以包装成一个lambda,可以不带参数地调用它:

int main() {
    auto x = invoke_and_measure([](){ return sum(1,2);});
    std::cout << x;
}

Live example

请注意,与bind相比,lambda通常更易于使用。 bind在某些极端情况下可以执行,但不能执行lambda,但实际上我从头顶上一无所知;)

答案 2 :(得分:2)

您可以执行以下操作:

template<typename F, typename ... Ts>
auto invoke_measure_time(F&& f, Ts&&... args)
{
    auto start = std::chrono::system_clock::now();
    auto f_result = std::invoke(std::forward<F>(f), std::forward<Ts>(args)...);
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start);

    return std::make_pair(duration, f_result);
}

Demo

f返回void的情况下,顺便说一句。