Как вернуть лямбда-функцию?

Например, я могу определить лямбда-функцию как

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 )>. При вызове его может потребоваться дополнительная функция вызова функции, которая в большинстве случаев является незначительной.