C ++ изменить указатель на параметры функции, чтобы быть параметром массива - PullRequest
0 голосов
/ 03 июля 2018

У меня есть класс с массивом, размер которого указан в конструкторе. Класс также хранит указатель на функцию, которая принимает указатель в качестве параметра, который при вызове будет установлен для указания на массив. У меня также есть функция «bind», которая устанавливает указатель на функцию, равный некоторой другой функции, переданной в качестве параметра. Это позволяет мне связывать произвольные функции, параметры которых будут содержать массив. Это выглядит так:

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[]);
};

Это работает отлично и все, но смысл использования массивов (или любого типа контейнера) заключался в том, чтобы классы, наследуемые от MyClass, могли указывать явный размер. Затем я планировал (каким-то образом) переопределить функцию bindFunc, чтобы получить указатель на функцию, которая имеет явное количество отдельных параметров вместо указателя на функцию с массивом параметров. Это просто для очистки синтаксиса и скрытия реализации производного класса. Это будет выглядеть примерно так:

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

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

Ошибка возникает, когда fn = func, поскольку fn - это указатель на функцию, которая принимает массив (указатель) в качестве параметра, а func - это указатель на функцию, которая принимает 2 типа double в качестве параметров. Это суть проблемы, которую я не знаю, как решить.

Конечно, в этом фрагменте я немного уменьшил код, чтобы он содержал только соответствующие части, и переименовал все, чтобы лучше описать мою проблему. Если это помогает, первоначальная цель класса состояла в том, чтобы хранить информацию о состоянии, переданную из функций обратного вызова GLFW. Производный класс (ы) должен был содержать информацию о позиции прокрутки и мыши соответственно (1 элемент для позиции прокрутки, 2 элемента для позиции X / Y мыши, следовательно, массив, размер которого установлен в конструкторе производного класса.) Базовый класс также имелись функции для вычисления других вещей, таких как дельты, которые любой другой мыслимый тип ввода переменных нашел бы полезным, следовательно, абстракция иерархии. Все это должно было упростить обработку ввода и выглядело бы примерно так при использовании:

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*/
}

Я не уверен, возможно ли то, что я хочу, но мне интересно узнать больше об этом или о более правильном шаблоне проектирования. Я пытался поиграться с <functional> функциями, но сам ничего не смог придумать. Такое ощущение, что в языке есть какая-то особенность, которая делала бы что-то подобное, вот почему я решил напечатать этот вопрос для начала.

Большая часть того, что я экспериментирую в C ++, предназначена для обучения, и я знаю, что мои методы могут быть немного безумными для того, чего я пытаюсь достичь, но надеюсь, что это приведет к тому, что я стану лучшим программистом. Спасибо за ваше понимание заранее!

1 Ответ

0 голосов
/ 03 июля 2018

Если вы используете std::function вместо необработанных указателей на функции, вы можете использовать лямбду для перевода аргументов любым способом:

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]); }; }

для большей гибкости вы можете сделать аргумент func также std::function

...