Страницы

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

суббота, 6 октября 2018 г.

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

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


Ответ

В современном 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() << '
'; // 5
auto fn_half = std::bind (my_divide,_1,2); // returns x/2 std::cout << fn_half(10) << '
'; // 5
auto fn_invert = std::bind (my_divide,_2,_1); // returns y/x std::cout << fn_invert(10,2) << '
'; // 0.2
auto fn_rounding = std::bind (my_divide,_1,_2); // returns int(x/y) std::cout << fn_rounding(10,3) << '
'; // 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) << '
'; // 20
auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a std::cout << bound_member_data() << '
'; // 10
return 0; }

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

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