Хорошая практика для передачи функции в качестве параметра: copy, reference, const reference?

Возможный дубликат:
передача шаблона по значению или константной ссылке или…?

Что является хорошей практикой для функции, принимающей функцию в качестве параметра:

template<class Function> void test1(Function f);
template<class Function> void test2(Function& f);
template<class Function> void test3(const Function& f);

где переданная функция может быть функтором, функцией std :: function, указателем функции или лямбда-функцией.

3

Решение

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

template<class Function> void test(Function&& f);
6

Другие решения

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

  1. template <typename T> void f(T&& a)
  2. template <typename T> void f(T& a)
  3. template <typename T> void f(T const& a)
  4. template <typename T> void f(T a)

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

Если f() фактически что-то делает с объектом, обычно мы можем сразу отказаться от двух опций:

  1. Проход по универсальной ссылке приводит к типу, который мы не знаем, является ли это ссылкой или значением. Это довольно бесполезно ни для чего, кроме пересылки типа, так как он ведет себя как значение или как ссылка. Просто указать, что на самом деле делает функция, было бы проблематичным танцем.
  2. Проходить мимо T const& нам тоже не очень хорошо: мы получили ссылку на объект, время жизни которого мы не можем контролировать и от которого мы не можем ни переместиться, ни получить его копирование / перемещение.

Передача объектаconst ссылка может быть полезна, если сам объект изменяется. Это, безусловно, важная часть контракта функции и навязанный выбор дизайна, который не может быть отменен клиентом функции при его выполнении.

Предпочтительный подход — принимать аргументы по значению. Как правило, это значительно упрощает определение поведения функции и фактически оставляет выбор, должен ли тип следовать за значением или ссылочной семантикой, открытой для пользователя! То, что что-то передается по значению, не означает, что объекты, представляющие интерес, также передаются по значению. Специально для случая объекта функции стандартная библиотека C ++ даже предоставляет универсальный адаптер, предоставляющий семантику ссылки на тип значения: std::ref(),

Конечно, дизайн интерфейса тонкий, и будут случаи, когда каждый из вариантов оправдан. Однако, как правило, я думаю, что это очень просто:

  1. Функции пересылки используют универсальные ссылки.
  2. Функции, выполняющие что-либо с аргументами, используют значения.

… и, конечно, эти правила применяются только к аргументам шаблонов функций, тип которых выводится.

4

По вопросам рекламы [email protected]