Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use void parameter when using template in C++

Tags:

c++

I want to make a function to test the running time of the incoming function. I use templates to make it applicable to many functions.

I omitted the code for counting time. like this:

template<typename F>
void get_run_time(F func)
{
//time start
 func;
//time end
}

But if a function I pass in is void, an error will be report and prompt me to add F=void. I tried to add it, but it didn't work. I can change void to bool, but it's very strange.

Another problem is that I want to test a function time and run my whole code normally .So I increased the return value. like this:

template<typename F>
F get_run_time(F func)
{
//time start
 F tf=func;
//time end
 return tf;
}

But the actual test time is obviously wrong. I guess it starts to run the function when it return .How can it get the running results before continuing with the following code?

like image 858
jerx Avatar asked Dec 06 '25 17:12

jerx


2 Answers

The idiomatic C++ way (as I see it) is this

template <class F>
auto call(F f)
{
  Timer t;
  return f();
}

This works with functions returning void. Note, no start and stop here. Timer is a RAII class that starts the timer on construction and stops on destruction.

Forwarding parameters to f and niceties like std::invoke are not shown for brevity.

like image 123
n. 1.8e9-where's-my-share m. Avatar answered Dec 08 '25 16:12

n. 1.8e9-where's-my-share m.


First, you need to call the passed function to actually time its execution. Note, in your code you do not call it, using the () call operator:

template <typename Func>
void timer1 (Func func)
{
    // start timer
    func(); 
    // stop timer
}

Second, note these nuances:

// Will take the same time as the timer1
template <typename Func>
Func timer2 (Func func1)
{
    // func2 is a copy of func1
    // This copying won't increase the time as you thought it will
    Func func2 = func1;
    // You still need to call the function
    func2();

    // Returns pointer to function
    return func2;
}

void foo() { std::cout << "foo()" << std::endl; }

int main() {
    // Func, here, is a type void (*)()
    // Prints "foo()"
    timer2(foo);    
}

Third, you may want to look toward this approach:

// Since C++14
auto timer3 = [](auto&& func, auto&&... args)
{
    // start timer

    // Forward the func and invoke the call operator
    // with however many forwarded arguments passed to the timer3
    std::forward<decltype(func)>(func)(std::forward<decltype(args)>(args)...);

    // stop timer
};

void foo(int, int) {}

int main() 
{
    timer3(foo, 21, 42);    
}

Even more proper and concise way to do the job, as noted by the @JHBonarius, is to use the std::invoke (since C++17), which was covered in this thread: What is std::invoke in C++?

like image 25
rawrex Avatar answered Dec 08 '25 16:12

rawrex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!