Страницы

Поиск по вопросам

воскресенье, 1 декабря 2019 г.

Массив функций: можно ли реализовать?

#cpp #массивы


Можно ли в C++ реализовать массив функций? То есть, в массив можно записать функции
a(), b() и c() (не сами функции, а операторы для их вызова), а затем вызывать их, как
будет удобно. Если нет, то можно вызывать ту функцию, которая указана в аргументах?
    


Ответы

Ответ 1



В современном c++ присутствуют удобные средства для оперирования функциями как функциональными объектами. Посмотрите functional, а именно std::function и std::bind. По указанным ссылкам также находятся очень хорошие примеры. Разумеется в c++ можно работать и с голыми указателями на функции (свободные и функции-члены класса), но это не так удобно и просто. Особенно при построении пользовательского интерфейса. Пример массива функций. В качестве массива используем стандартный контейнер std::vector. Ниже продемонстрировано как можно для более узкой сигнатуры функции использовать более широкое определение. Известно что вызывающая сторона ожидает сигнатуру void(int), а мы будем ей передавать void(int, int) и void(const std::string&, int, int). #include // std::cout #include // std::bind #include #include void a(int x, int y) { std::cout << "a(" << x << ", " << y << ")" << std::endl; } void b(int x, int y) { std::cout << "b(" << x << ", " << y << ")" << std::endl; } void c(const std::string& s, int x, int y) { std::cout << "c(" << s << ", " << x << ", " << y << ")" << std::endl; } int main () { using namespace std::placeholders; // adds visibility of _1, _2, _3,... std::vector> functions; // создаем и помещаем в вектор функциональный объект, во время вызова необходимо передать один аргумент functions.emplace_back(std::bind(a, _1, _1)); functions.emplace_back(std::bind(a, _1, 42)); functions.emplace_back(std::bind(a, _1, 100500)); functions.emplace_back(std::bind(b, _1, 42)); functions.emplace_back(std::bind(b, 42, _1)); functions.emplace_back(std::bind(c, "Hello world!", _1, 3)); int i = 0; for (const auto& fn : functions) { fn(i++); } return 0; } Вывод. a(0, 0) a(1, 42) a(2, 100500) b(3, 42) b(42, 4) c(Hello world!, 5, 3) Еще один пример (взят с www.cplusplus.com): // bind example #include // std::cout #include // std::bind // a function: (also works with function object: std::divides my_divide;) double my_divide (double x, double y) {return x/y;} struct MyPair { double a,b; double multiply() {return a*b;} }; int main () { using namespace std::placeholders; // adds visibility of _1, _2, _3,... // binding functions: auto fn_five = std::bind (my_divide,10,2); // returns 10/2 std::cout << fn_five() << '\n'; // 5 auto fn_half = std::bind (my_divide,_1,2); // returns x/2 std::cout << fn_half(10) << '\n'; // 5 auto fn_invert = std::bind (my_divide,_2,_1); // returns y/x std::cout << fn_invert(10,2) << '\n'; // 0.2 auto fn_rounding = std::bind (my_divide,_1,_2); // returns int(x/y) std::cout << fn_rounding(10,3) << '\n'; // 3 MyPair ten_two {10,2}; // binding members: auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply() std::cout << bound_member_fn(ten_two) << '\n'; // 20 auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a std::cout << bound_member_data() << '\n'; // 10 return 0; }

Ответ 2



Конечно можно! double (*funcs_array[64])(int a, float b); Однако обычно, чтобы не запутаться, я объявляю тип указателя на функцию отдельным псевдонимом. Тогда объявление массива таких указателей не отличается от объявления массива либого другого типа. typedef double (*FuncPtr)(int a, float b); FuncPtr funcs_array[64]; Про указатели на функции неплохой стартовый пост был у Алены.

Ответ 3



Имя функции в Си++ - это такой же указатель как и все прочие. Соответственно можно собрать их в массив. Главное с аргументами не перемудрить

Ответ 4



Конечно можно создавать массивы функций и вызывать их из массива. Посмотрите мой код с комментариями как это делается. #include using namespace std; // Создаем три функции с одинаковым количеством параметров // и соответствующими типами, а так же возращаемым типом int sum(const int a, const int b){ return a + b; } int sep(const int a, const int b){ return a - b; } int mul(const int a, const int b){ return a * b; } typedef // создаем новый прототип (в данном случае указатель на функцию) int // возвращаемое значение (такое же как в функциях) (*func) // имя прототипа (в коде употребляется без звездочки) (const int, const int); // список параметров (такое же как в функциях) int main(){ func arr[3]; // обьявляем массив функций из трех элементов // помещаем в массив функции указывая их имена (потому что имя функции это и есть указатель на нее) arr[0] = sum; arr[1] = sep; arr[2] = mul; // используем указатели из массива (выводим результат функций в массиве с конкретными параметрами) cout << arr[0](5, 2) << endl; cout << arr[1](5, 2) << endl; cout << arr[2](5, 2) << endl; return 0; }

Комментариев нет:

Отправить комментарий