Как вернуть лямбда-функцию?
Например, я могу определить лямбда-функцию как
auto f = [](double value) {double ratio = 100; return value * ratio;}
Теперь я хочу сгенерировать функцию с отношением аргументом и вернуть функцию лямбда, например
auto makeLambda(double ratio) { return [=](double value) {return value * ratio;}; }
Как это сделать?
Ответы
Ответ 1
С выводом типа возвращаемого типа функции С++ 14, который должен работать.
В С++ 11 вы можете определить другую лямбду (которая может выводить тип возврата), а не функцию (которая не может):
auto makeLambda = [](double ratio) {
return [=](double value) {return value * ratio;};
};
Как отмечено в комментариях, это может быть дополнительно завершено, если вам особенно нужна функция:
auto makeLambdaFn(double ratio) -> decltype(makeLambda(ratio)) {
return makeLambda(ratio);
}
Ответ 2
@disclaimer: этот ответ просто добавляет дополнительные аргументы в ответ @Slava (но слишком длинный для комментария).
Вероятно, вы не должны возвращать лямбда, но указатель на функцию или функцию std::.
Эффективность касается asside (см. ниже), декларация API должна рассказать вам, как ее использовать. Лямбда - это временная функция - что-то предназначенное, чтобы иметь смысл, где вы ее используете (в локальном контексте).
Если вы пишете это:
std::function<double( double )> makeFunction(double ratio);
Ваш код будет намного более гибким (не зависящим от С++ 14), гораздо лучше определенным (вы можете посмотреть подпись и узнать, что она делает) и будущим (легко понять намерение API, который упрощается для дальнейшего распространения, не закручивая клиентский код).
Если вы пишете это:
auto makeFunction(double ratio);
Вы должны определить его встроенный (я думаю).
Для реализации, подобной ответу MikeSeymour, вам нужно добавить дополнительную лямбду, чтобы избежать ограничения компилятора. Чтение реализации с помощью лямбда, возвращающего лямбда только для того, чтобы понять, что возвращает API, - это большой нет-нет.
Во-первых, потому что это неочевидно и неясно.
Во-вторых, он будет налагать на клиентский код, API, который либо нуждается в комментариях/пояснительной записке, чтобы иметь смысл, либо заставляет клиентов читать эту реализацию, чтобы знать, как ее использовать.
Если вы не можете гарантировать, что это код выброса, вы будете:
-
увеличить коэффициент WTF/SLOC вашего кода (код нечеткий, если вам нужно прочитать реализацию, чтобы выяснить, что она возвращает)
-
есть что-то неочевидное, что вам нужно будет поддерживать для всего проекта. Это называется cruft, и это то, что делает sucky legacy code sucky устаревшим кодом).
Если вам нужно вернуть функтора, вам лучше вернуться std::function
; Тип возврата практически кричит "возврат функтора".
Если это слишком неэффективно для ваших нужд, вы можете его оптимизировать/уточнить позже), например, возвращая экземпляр struct X { double operator()(double); }
.
Замечание о возможности гарантировать, что это не производственный код:
Я видел много случаев, когда:
-
Я смотрел на ужасный трехлетний код, где люди говорили мне , первоначально это был прототип, но мы показали приложение своим клиентам, они попросили его "как есть" и теперь клиенты зависят от него, но у нас нет бюджета времени для его очистки..
-
Я отправил уродливый код прототипа кому-то другому (как в "мы могли бы сделать что-то, что следует за этим алгоритмом" ), и увидели, что оно было передано позже в качестве решения в управлении версиями.
-
Люди писали хаки над хаками, потому что код уже был взломан, и еще один взломать не имеет значения (это очень распространенное извинение на самом деле).
Ответ 3
Вы можете вернуть std::function<double( double )>
. При вызове его может потребоваться дополнительная функция вызова функции, которая в большинстве случаев является незначительной.