Home > Enterprise >  How to pass non-static member function pointer to a template function in C ?
How to pass non-static member function pointer to a template function in C ?

Time:10-23

I'm trying to make a function template in a header file that accepts a generic function pointer and packed arguments. The function template would invoke the received function pointer using the packed arguments. My goal is to calculate and return the execution time of the function pointer.

#ifndef LOGTIME_HPP
#define LOGTIME_HPP

#include <chrono>
#include <ratio>

template<typename Function, typename... Args>
double getExecutionTime(Function&& function, Args&&... args) {
    auto t1 = std::chrono::high_resolution_clock::now();
    std::invoke(std::forward<Function>(function), std::forward<Args>(args)...);
    auto t2 = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> ms = t2 - t1;
    return ms.count();
}

#endif

This seems to only work for function pointers that aren't member functions of a class or struct. This is some example code using the function template:

#include <iostream>
#include <thread>
#include <random>

#include "LogTime.hpp" // header including getExecutionTime()

class Obj
{
public:
    int testFunc(int dur, int num) {
        std::cout << "test" << num;
        for (int i = 0; i < dur; i  ) {
            std::cout << ".";
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
        }
        return 2;
    }
};

int testFunc(int dur, int num) {
    std::cout << "test" << num;
    for (int i = 0; i < dur; i  ) {
        std::cout << ".";
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
    return 1;
}

int main()
{
    std::random_device dev;
    std::mt19937 rng(dev());
    std::uniform_int_distribution<> uniform_dist(1, 100);

    Obj obj = Obj();

    for (int i = 0; i < 10; i  ) {
        int rand = uniform_dist(rng);
        std::cout << "elapsed: "
            // this works
            << getExecutionTime(testFunc, uniform_dist(rng), i) << std::endl;
            
            // this doesn't work 
            << getExecutionTime(Obj::testFunc, uniform_dist(rng), i) << std::endl;
    }
}

My issue is that Obj::testFunc is failing. I know that if Obj::testFunc was static, then the function would execute fine. I've read that std::invoke can invoke a member function by passing an instance of the class type. However, I don't know how to incorporate this into the function template (I've never used templates before now).

I would appreciate any help or insight.

CodePudding user response:

Non-static member functions have an implicit parameter of the class type as the first parameter of the function, and it is that object which is mapped to the this pointer. That means that you need to pass an object of the class type as the first argument after the member function pointer like

<< getExecutionTime(&Obj::testFunc, obj, uniform_dist(rng), i) << std::endl;

or you can use a lambda instead like

<< getExecutionTime([&](){ obj.testFunc(uniform_dist(rng), i); }) << std::endl;
  • Related