Передача имени функции в качестве аргументов функции

Можно ли передать имя функции (скажем, A) в качестве аргумента другой функции (скажем, B), а затем вызвать функцию A из функции B. То есть имя функции будет храниться в переменной в B, и использование он вызывает функцию, имя которой находится в переменной. Например, в функции сортировки C++ первый и второй аргументы — это итераторы, а третий аргумент — это имя функции.


person Balanivash    schedule 15.06.2011    source источник
comment
Связано: stackoverflow.com/questions/47502068/   -  person alseether    schedule 04.12.2017


Ответы (5)


Вы можете ввести параметр шаблона (здесь Pred) для «всего, что можно вызвать с двумя параметрами»:

template <typename Iter, typename Pred>
void mysort(Iter begin, Iter end, Pred predicate)
{
    --end;
    // ...
        if (predicate(*begin, *end))
        {
            // ...
        }
    // ...
}

Затем вы можете передать либо старые добрые указатели функций C, либо объекты функций C++:

bool function(int x, int y)
{
    return x < y;
}

struct function_object
{
    bool operator()(int x, int y)
    {
        return x < y;
    }
};

int main()
{
    int numbers[] = {543, 6542654, 432514, 54, 45, 243};
    mysort(numbers + 0, numbers + 6, &function);
    mysort(numbers + 0, numbers + 6, function_object());
}

Как видите, объект функции — это объект класса, который соответствующим образом перегружает operator().

person fredoverflow    schedule 15.06.2011
comment
mysort(numbers + 0, numbers + 6, function); также должен работать, поскольку функция неявно преобразуется в указатель на себя. - person Mihai Todor; 16.06.2015
comment
Можем ли мы использовать шаблонный метод для функций, требующих 4-5 параметров? - person Alpha Mineron; 06.09.2017
comment
@AlphaMineron Конечно, параметр Pred predicate не предъявляет никаких требований к типу Pred. Только при использовании if (predicate(*begin, *end)) компилятор проверит, что его можно вызывать с двумя аргументами. Если вам нужно 5 аргументов, просто вызовите его с 5. - person fredoverflow; 06.09.2017

Вы должны прочитать об указателях функций.

person mdm    schedule 15.06.2011

простой пример с указателями функций:

#include <iostream>

int apply(int (*fun)(int,int), int a, int b) {
    return (*fun)(a,b);
}

int add(int a, int b) {return a + b;}
int multiply(int a, int b) {return a * b;}

int main(int argc, const char* argv[]) {
    int added = apply(add, 2, 4);
    int multiplied = apply(multiply, 2, 4);

    std::cout << "added result: " << added << std::endl;
    std::cout << "multiplied result: " << multiplied << std::endl;
}

выход:

added result: 6
multiplied result: 8
person Electric Coffee    schedule 27.10.2013

Да, это не только возможно, но и широко используется.

Технически они известны как указатели функций.

Концептуально они должны иметь механизмы обратного вызова. Обратные вызовы могут потребоваться для программ, управляемых событиями. Например, вашему приложению может быть интересно узнать, когда нажата кнопка мыши. В этом случае вы должны зарегистрировать свой интерес к базовой платформе для события щелчка мыши и сообщить ей, какой метод/функцию следует вызывать в вашей программе, чтобы вы могли выполнить код соответствующим образом.

Другой такой случай — когда программы имеют асинхронный режим выполнения. Например, в случае, если файл необходимо записать на жесткий диск, что является трудоемким процессом по сравнению с выполнением арифметических вычислений. Таким образом, это может быть случай, когда мы не хотим ждать выполнения вычислений, пока мы записываем результаты в файл. Программа может просто вызвать функцию write для файла, вернуться и начать вычисления. При вызове этой функции вызывающая сторона может также указать функцию обратного вызова. Таким образом, при успешной или неудачной записи файла вызывается функция обратного вызова, и вызываемый информируется соответствующим образом.

person Ozair Kafray    schedule 15.06.2011

Да, это возможно. Технически передается не совсем «имя», а фактически указатель на передаваемую функцию.

person Delan Azabani    schedule 15.06.2011