Когда использовать шаблон функции вместо универсальной лямбда-выражения?

Я могу написать шаблон функции:

template<typename T>
void f1(T parameter) { ... }

Но в C++14 я также могу создать общую лямбду:

auto f2 = [](auto parameter) { ... };

В пределах f1 я могу напрямую ссылаться на T. Внутри f2 нет T для ссылки, но я могу получить тот же эффект, используя decltype:

auto f2 = [](auto parameter)
          {
            using T = decltype(param);
            ...
          };

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

template<typename T>
void fwdToG(T&& param) { g(std::forward<T>(param)); }

fwdToG(f1);        // error!
fwdToG(f2);        // okay

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


person KnowItAllWannabe    schedule 05.04.2014    source источник
comment
Подожди, ты не можешь? Почему одна универсальная ссылка, а другая нет? В чем ошибка? И какую проблему это представляет для вас? Что такое g?   -  person Lightness Races in Orbit    schedule 05.04.2014
comment
g — это какая-то другая функция, которую я хочу вызвать; fwdToG — это функция идеальной переадресации. Ошибка в том, что f1 не имеет типа (это шаблон, а не функция), поэтому попытка передать его fwdToG не удалась.   -  person KnowItAllWannabe    schedule 05.04.2014
comment
Ах, да, хорошо. Ну разве это не ответ на ваш вопрос?   -  person Lightness Races in Orbit    schedule 05.04.2014
comment
То, что я показал, было преимуществом общих лямбда-выражений над шаблонами функций. Я спрашиваю, есть ли преимущества у шаблонов функций по сравнению с общими лямбда-выражениями.   -  person KnowItAllWannabe    schedule 05.04.2014
comment
Справедливо. Чего это стоит, я не могу придумать.   -  person Lightness Races in Orbit    schedule 05.04.2014
comment
Лямбда-выражения должны быть привязаны к переменным, а функции — нет.   -  person Rapptz    schedule 05.04.2014
comment
@lightness я ошибаюсь, и можно ли найти вызовы лямбда через ADL?   -  person Yakk - Adam Nevraumont    schedule 08.04.2014
comment
@Yakk: Похоже, нет, если только я что-то не упустил.   -  person Lightness Races in Orbit    schedule 08.04.2014


Ответы (1)


Функции template позволяют перегружать другие функции с тем же именем, и их вызов работает через ADL. Общие лямбда-выражения — это объекты с перегруженным (), поэтому ни один из них не работает.

Вы можете довольно легко передать перегрузку функции, установленную для объекта:

 struct foo_overload_set_t {
   template<class...Ts>
   constexpr auto operator()(Ts&&...ts)const{ return foo(std::forward<Ts>(ts)...); }
 };

который с помощью RVO можно полностью оптимизировать (нулевые накладные расходы), а экземпляр всего набора перегрузок можно передать алгоритму. Вы также можете сделать это с помощью лямбды в точке использования, которая может быть сгенерирована макросом.

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

person Yakk - Adam Nevraumont    schedule 05.04.2014
comment
Можете ли вы привести пример того, что вы подразумеваете под передачей функции перегруженного набора? - person KnowItAllWannabe; 05.04.2014
comment
@knowitallwannabe std::sort(it1,it2,foo_overload_set_t{}) выполнит поиск перегрузки и вызовет foo внутри std::sort. По сути, вы можете обернуть поиск правильной перегрузки в объект, который можно передавать. - person Yakk - Adam Nevraumont; 05.04.2014
comment
@knowitallwannabe Обратите внимание, что я недостаточно подчеркнул два преимущества: перегрузку (за пределами class, поэтому распределенную) и ADL (поэтому перегрузку за пределами пространства имен!) Два из них позволяют вам писать код рядом с тем, где он должен быть, а не где язык диктует, что это должно быть. - person Yakk - Adam Nevraumont; 06.04.2014
comment
Я думаю, что функции перегрузки и ADL очевидны в вашем ответе, за который я проголосовал. - person KnowItAllWannabe; 06.04.2014
comment
Означает ли это, что в целом следует отдавать предпочтение шаблонам функций? Или есть очевидные ситуации, когда универсальная лямба лучше (кроме аргумента прямой функции)? - person Walter; 23.10.2015
comment
@Walter Хотите ли вы иметь перегрузки и / или ADL или нет? Вы хотите возиться с приведенной выше конструкцией набора перегрузок или нет? Вызывает ли идеальная пересылка в этой конструкции набора перегрузки проблемы или нет? - person Yakk - Adam Nevraumont; 23.10.2015