#новичкам
В С++ полно вещей, которые можно вызывать, как функции. Но, как мы убедились в прошлый раз, не только функции в плюсах можно "вызывать". Хотя указатели на поля класса - это единственное такое исключение, давайте перечислим все вызываемые сущности в С++. Поехали!
👉🏿 Функции. Старые-добрые и всем знакомые функции. Очевидный кандидат:
void free_function(int a) {
std::cout << "Free function: " << a << std::endl;
}
free_function(42);👉🏿 Указатели на функцию
Если вы хотите куда-то передать функцию, как коллбэк, то скорее всего стриггерите неявное приведение имени функции к указателю на функцию. Вот так например:
void free_function(int a) {
std::cout << "Free function: " << a << std::endl;
}
std::invoke(free_function, 42);Внутрь invoke free_function передастся как именно как указатель.
Указатель на функцию можно и явно определить и вызвать с его помощью соответствующей функции:
auto fun_ptr = &free_function;
fun_ptr(42);
(*fun_ptr)(42);
Когда мы просто передаем имя функции в call_callback, это имя приводится к типу указателя на функцию:
void free_function(int a) {
std::println("Free function: {}", a);
}
call_callback(free_function, 42);👉🏿 Ссылки на функции
Да, и такие тоже есть:
auto& fun_ref = free_function;
fun_ref(42);
(*fun_ref)(42); // интересно, что такой синтаксис разрешен
Если передать в функцию в качестве параметра по ссылке, то тогда тоже получите ссылку на функцию:
void check_name(auto& obj) {
// by passing free_function to check_name, obj become function reference
}
check_name(free_function);👉🏿 Статические методы классов
struct Handler {
static void static_method(int a) {
std::cout << "Static method: " << a << std::endl;
}
};
Handler::static_method(42);Также мы можем явно определить указатель или ссылку на статический метод класса, так как это обычная функция:
auto static_method_ptr = &Handler::static_method;
std::invoke(static_method_ptr, 42);
👉🏿 Функциональные объекты
В обывательском понимании функторы - это объекты классов с определенным оператором(). Однако не все так просто. На самом деле с точки стандарта функциональный объект - это одно из 3-х: указатель на функцию, объект класса с определенным оператором() и объект класса с определенным оператором приведения к указателю на функцию. Их всех объединяет одинаковый синтаксис вызова, поэтому их засунули в одну категорию. Указатели на функции мы разобрали, рассмотрим 2 оставшихся.
👉🏿👉🏿 Объект класса с определенным вызова operator(). Это такие стандартные олдскульные(до С++11) функторы, которые использовались, например, для передачи в стандартные алгоритмы. Название, в общем, полностью описывает реализацию. Единственное, что хочется отметить - необходимость таких функторов заключена в их способности хранить стейт, иначе можно было использовать обычные функции.
class SequenceGenerator {
int current;
int step;
public:
SequenceGenerator(int start = 0, int step_size = 1)
: current(start), step(step_size) {}
// Оператор вызова без аргументов - возвращает следующее число
int operator()() {
int val = current;
current += step;
return val;
}
};
SequenceGenerator gen;
std::vector<int> numbers(5);
std::generate(numbers.begin(), numbers.end(), gen); // заполняем вектор с помощью функтораУже много получилось, все в один пост не влезет. Поэтому в следующих раз будет продолжение.
Have all the tools. Stay cool.
#cppcore