Search code examples
c++arraysfunction-pointerstype-mismatchfunction-binding

C++ change pointer to function's parameters to be an array parameter


I have a class with an array who's size is specified in the constructor. The class also stores a pointer to a function that takes a pointer as a parameter which, when called, will be set to point to the array. I also have a "bind" function which sets the function pointer equal to some other function passed in as a parameter. This allows me to bind arbitrary functions who's parameters will contain the array. It looks like this:

template <typename T>
class MyClass{
public:
    MyClass(int s) : size(s) { arr = new T[size]; }
    MyClass() { delete[] arr; }

    virtual inline void bindFunc(void(*func)(T[])) { fn = func; } //types match, ok
    inline void callFunc(){fn(arr);} 
        /*Yes, I know I need a size parameter to correctly
        iterate over arr, I took out this info to help make things more clear, just pretend 
        arr is null terminated and the bound fn function knows how to correctly handle it*/

private:

    const int size; 
    T arr[];
    void(*fn)(T[]);
};

This works fine and all, but the point of using arrays (or any container type) was so classes that inherit from MyClass can specify an explicit size. I then planned to (somehow) override the bindFunc function to take a pointer to a function that has an explicit number of separate parameters instead of a pointer to a function with an array of parameters. This is simply to clean up the syntax and make the derived class hide implementation. It would look something like this:

class derived: public MyClass<double> {
public:
    derived() : MyClass(2) {}

    inline void bindFunc(void(*func)(double, double)) { fn = func; } //error, type mismatch, obviously
};

The error occurs where fn = func because fn is a pointer to a function that takes an array(pointer) as a parameter and func is a pointer to a function that takes 2 doubles as parameters. This is the crux of the problem that I do not know how to fix.

Of course, in this snippet I slimmed down the code a bit to only contain the relevant parts and renamed everything to better portray my problem. If it helps, the original purpose of the class was to store state information passed in from GLFW's callback functions. The derived class(es) were supposed to hold scroll and mouse position info respectively (1 element for scroll position, 2 elements for mouse X/Y position, hence the array who's size is set in the derived class' constructor.) The base class also had functions for calculating other things such as deltas that any other imaginable type of variable input would find useful, hence the hierarchy abstraction. This was all meant to simplify input handling and would've looked something like this when being utilized:

void mouse_callback(GLFWwindow*, double, double);
glfwSetCursorPosCallback(window, mouse_callback);

MyClass *MouseInput = new derived;

void mouseFunction(double x, double y){ //takes 2 doubles instead of array of doubles of size 2
    if(x > 0.5)
        //do something
    if(y < 0.5)
        //do something else
}

void main(){
    MouseInput->bindFunc(mouseFunction);
    MouseInput->callFunc();
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
    MouseInput->setInfo(xpos, ypos);
        /*this function is not shown in the code above, but it basically sets
        MouseInput->arr's variables and calls a base class' calculation function
        to calculate extra info such as the aforementioned deltas*/
}

I'm not sure if what I want is possible, but I'm interested in learning more about it or a more correct design pattern. I've tried fiddling around with <functional> functions, but I couldn't come up with anything myself. It feels like there would be a feature to the language that would make something like this possible, which is why I cared to type up this question to begin with.

Most of what I experiment with in C++ is for learning and I know my methods might be a little insane for what I'm trying to accomplish, but the hope is it will lead to being a better programmer. Thanks for your insight in advance!


Solution

  • If you use std::function instead of raw function pointers, you can use a lambda to translate the arguments in any way you want:

    template <typename T>
    class MyClass{
        std::function<void(T[])>  fn;
    public:
    
    virtual inline void bindFunc(void(*func)(T[])) { fn = func; } //types match, ok
    virtual inline void bindFunc(void(*func)(T, T)) {
        fn = [func](T args[]) { func(args[0], args[1]); }; }
    

    for more flexibility, you can make the func argument a std::function as well