У меня есть класс с массивом, размер которого указан в конструкторе. Класс также хранит указатель на функцию, которая принимает указатель в качестве параметра, который при вызове будет установлен для указания на массив. У меня также есть функция «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 ++, предназначена для обучения, и я знаю, что мои методы могут быть немного безумными для того, что я пытаюсь достичь, но надеюсь, что это приведет к тому, что я стану лучшим программистом. Спасибо за ваше понимание заранее!
Если вы используете 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
также
Других решений пока нет …