Ссылки на функции - PullRequest
       20

Ссылки на функции

47 голосов
/ 26 января 2009

Итак, я просто работал с указателями на функции и вспомнил, что вы можете сделать это:

void Foo()
{
}

int main()
{
    void(& func)() = Foo;

    func(); //::Foo();
}

Очевидным преимуществом является то, что ссылки ссылаются на действительные объекты (если они не используются неправильно) или функции в этом случае.

Очевидными недостатками является то, что вы не можете хранить массив ссылок и не можете использовать их для указателей на функции-члены (по крайней мере, насколько я могу судить).

Мой вопрос: кто-нибудь их использует (например, ссылки на функции , не указатели на функции), и если да, то в каких сценариях вы их нашли полезным / полезным?

Единственное место, где я могу видеть, что они полезны вне сети, - это привязка ссылки к определенной функции при работе с условной компиляцией.

Ответы [ 5 ]

13 голосов
/ 26 января 2009

Я использовал их раньше, чтобы добавить настройку к классам, передавая их конструктору таким образом, как шаблон стратегии

12 голосов
/ 26 января 2009

Я думаю, что ваш пример использования довольно хорош. Потому что, если бы вы использовали обычный указатель на функцию, а затем применили оператор address-of, вы бы получили адрес указателя на функцию. Использование ссылки на функцию сделает ожидаемое, поскольку она возвращает указатель на саму функцию.

Я тоже не могу придумать много примеров. Как вы указали, сохранение ссылок на функции имеет некоторые ужасные последствия. Другим, возможно, нежелательным следствием является то, что если вы сохраните его в качестве члена класса, ваши объекты не будут назначаться, если вы не напишите свой собственный оператор = и воздержитесь от попыток переназначить ссылку на функцию.

Я думаю, что большинство использований ссылок на функции являются неявными, очень похоже на большинство применений ссылок на массивы - хотя намного больше, когда вы принимаете аргументы путем ссылки:

template<typename T>
void do_something(T const& t) { ... }

Хотя прием массивов по ссылке имеет преимущество, заключающееся в том, что они не теряют информацию о размере, но явный прием функций по ссылке явно не имеет преимущества (по крайней мере, насколько я могу видеть). Я полагаю, что существование ссылок на функции в значительной степени оправдано идеалистическим представлением ссылки как псевдонима -наименования некоторого объекта или функции, а также тем фактом, что она позволяет передавать функции в такие шаблоны, которые принимают их аргумент. по ссылке.

Я бы, вероятно, избегал их использования, если бы не нуждался в них неизбежно. Указатели на постоянные функции также предоставляют не подлежащие переназначению функции вызова и, вероятно, позволят избежать путаницы, когда другие программисты, которые, возможно, не очень знакомы с этими языковыми нишами, читают ваш код. Стоит отметить, что Vandervoorde & Josuttis также рекомендуют избегать их, чтобы уменьшить путаницу (в своей книге «Шаблоны C ++ - Полное руководство»).

9 голосов
/ 16 февраля 2013

Ссылки на функции, в отличие от указателей на функции, затрудняют их создание из недопустимого источника. Это полезно, если вы создаете оболочку вокруг библиотеки C - код C ++ может взять функцию обратного вызова по ссылке и передать указатель на библиотеку C, если библиотека требует, чтобы переданный указатель не был NULL.

Это также удобный способ для псевдонима функции, особенно в C ++ 11, с новым ключевым словом auto:

#include <iostream>
#include <typeinfo>

void f(int i, char c)
{
    std::cout << i << ' ' << c << std::endl;
}

int main()
{
    std::cout << typeid(f).name() << std::endl; //FvicE
    f(0, '1');

    void (*pf)(int, char) (&f); //ugly
    std::cout << typeid(pf).name() << std::endl; //PFvicE
    (*pf)(2, '3');
    pf(4, '5'); //works, but I don't recommend it

    void (&rf)(int, char) (f); //still ugly
    std::cout << typeid(rf).name() << std::endl; //FvicE
    rf(6, '7');

    auto &af (f); //pretty, but only works in C++11
    std::cout << typeid(af).name() << std::endl; //FvicE, same as above
    af(8, '9');
}
2 голосов
/ 01 сентября 2012

в дополнение к использованию в качестве стратегии (как указал Роберт Гулд), я часто использую их на входе в (шаблон) метапрограммирования. Ссылка на функцию может быть легко найдена параметром шаблона; с этого момента он может проходить через несколько слоев (метапрограммирования) шаблонов. Конечно, это верно и для указателя на функцию, но ссылка - это псевдоним , и, таким образом, сообщает намерение более четко.

В качестве примера: при написании универсальной системы диспетчеризации команд для приложения необходимо объявить множество различных операций в виде команд. Мы можем использовать простую «функцию построения» в качестве внешнего интерфейса для клиентского кода. За кулисами эта функция компоновщика выбирает фактическую сигнатуру функции в качестве параметра шаблона, извлекает (путем метапрограммирования шаблона) фактический параметр и возвращает значения типа и, возможно, выбирает подходящую специализацию для хранения «сувенира» и «функтора отмены». Эти функторы могут быть сохранены либо как внутренние указатели функций, либо с использованием функциональных объектов boost или tr1 или C ++ 11. Таким образом, можно создать безопасный вызов типа команды и систему «отменить».

1 голос
/ 26 января 2009

Я использовал их в подключаемой системе, где подключаемые библиотеки DLL могли загружаться / выгружаться во время выполнения. Я бы искал известные символы в каждой DLL и приводил их к указателям на функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...