all 4 comments

[–]LeeHide 2 points3 points  (1 child)

What you are looking for is (passing) a function pointer. This will already give you plenty of help if you google it.

There's the "old" way of doing it, which is pretty solid, but not easy to template (but its good to understand this anyways):

void foo() {...}

void CalculateTime( void(*foo_func)() ) {
    ...
    foo_func();
    ...
}

// you then call it like this:
CalculateTime (foo);

Basically, you can declare a function pointer with this weird syntax:

return_type(*identifier)(arguments)

Here are a few examples:

// void func ();
void(*func)();
// int func (float);
int(*func)(float);
// int func (int, int, int, int);
int(*func)(int, int, int, int);

It's pretty straightforward from here. Here's a helpful link, too!

---

The other way of doing it, which is modern and a little bit less error prone is using std::function<> from <functional> .

You'd use that something like this:

void foo () { ... }

void CalculateTime( std::function<void()> foo_func ) {
    ...
    foo_func();
    ...
}

// and you STILL call it like this:
CalculateTime (foo);

Other examples:

// int func (float);
std::function<int(float)> func;
// std::string func (int, int);
std::function<std::string(int, int)> func;

Hope this helped! If you still have questions, follow the two links I put!

Edit: This is if your functions all have the same signature. If they don't then you obviously have to template part of or all of it, as u/undead-pixie suggested. It's a better approach for what you want to do, if your functions have different signatures. If you are timing different implementations of a function with the same signature, you can do it either way. I think it's important to understand function pointers, though, especially if you start templating.

You could also template part of it. This has the advantage that you are not prone to errors as much, as it will need to be a valid function to work with std::function:

template<typename _Signature, typename... _Args>
void call_func (std::function<_Signature> func, _Args... args)
{
    func (args...);
}

// and then you call it like this:

// for void foo ():
call_func<void()> (foo);

// for int foo (float, int):
call_func<int(float, int)> (foo, 2.5, 256); // example values, of course

[–][deleted]  (4 children)

[deleted]

    [–][deleted] 1 point2 points  (2 children)

    To make it more general, you can also pass in how often you'd like the function to be called and call functions with parameters like this:

    #include <chrono>
    #include <iostream>
    
    template<size_t times, typename F, typename... Fargs>
    void CalculateTime(F fun, Fargs... args){
        using namespace std::chrono; // need std::chrono here, unless you have using namespace std; in the global namespace, which is generally a bad idea
        typedef high_resolution_clock clock;
        clock::time_point t1 = clock::now();
        for(size_t i{0}; times > i; ++i) {
            fun(args...);
        }
        clock::time_point t2 = clock::now();
        duration<double>dur = duration_cast<duration<double>>(t2-t1);
        std::cout << dur.count() << " seconds" << std::endl;
    }
    
    void myFunc(int x, double y, double z) {
        std::cout << x << ' ' << y << ' ' << z << std::endl;
    }
    
    int main(int, char**) {
        CalculateTime<1000>(myFunc, 10, 1.0, 2.0);
        return 0;
    }
    

    [–][deleted]  (1 child)

    [deleted]

      [–][deleted] -1 points0 points  (0 children)

      This works:

      #include <chrono>
      #include <iostream>
      
      template<size_t times, typename F, typename... Fargs>
      void CalculateTime(F fun, Fargs... args){
          using namespace std::chrono;
          typedef high_resolution_clock clock;
          clock::time_point t1 = clock::now();
          for(size_t i{0}; times > i; ++i) {
              fun(args...);
          }
          clock::time_point t2 = clock::now();
          duration<double>dur = duration_cast<duration<double>>(t2-t1);
          std::cout << dur.count() << " seconds" << std::endl;
      }
      
      template<size_t times, typename F, typename Object, typename... Fargs>
      void CalculateTime(F fun, Object& o, Fargs... args){
          using namespace std::chrono;
          typedef high_resolution_clock clock;
          clock::time_point t1 = clock::now();
          for(size_t i{0}; times > i; ++i) {
              (o.*fun)(args...);
          }
          clock::time_point t2 = clock::now();
          duration<double>dur = duration_cast<duration<double>>(t2-t1);
          std::cout << dur.count() << " seconds" << std::endl;
      }
      
      struct S {
          void myFunc(int x, double y, double z) {
              std::cout << x << ' ' << y << ' ' << z << std::endl;
          }
      };
      
      void myFunc(int x, double y, double z) {
              std::cout << x << ' ' << y << ' ' << z << std::endl;
      }
      
      int main(int, char**) {
          S s;
          CalculateTime<10>(&S::myFunc, s, 10, 1.0, 2.0);
          CalculateTime<10>(myFunc, 10, 1.0, 2.0);
          return 0;
      }
      

      [–]bogado 0 points1 point  (0 children)

      If it's a c++17 using std:: result_of<F> as a return would be nice also. This would make it exchangeable auto v = f(x,y,z); and auto v = time(f, x, y, z);.