C ++ 11: лямбда, карри

У меня есть следующий код. Можете ли вы объяснить мне, как это работает?

template<typename Function, typename... Arguments>
auto curry(Function func, Arguments... args) {
return [=](auto... rest) {
return func(args..., rest...);
};
}

int main() {
auto add = [](auto x, auto y) {
return x + y;
};
auto add4 = curry(add, 4);
std::cout << add4(3) << '\n'; //output: 7. (Ok)

}

6

Решение

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

В основном это означает сокращение функция с определенным количеством параметров для создания другая функция с некоторыми фиксированными значениями параметра.

Я ваш пример, оригинальная функция add(x,y) который имеет два параметра Икс а также Y. Вы уменьшить Арность функции добавить, установив Икс до 4 и создать сокращенную функцию add4(y) такие как

add4 (y) = add (x, y) где х = 4

Теперь, как это достигается в вашем коде C ++? С помощью вариационные шаблоны, вариационные функции а также лямбда-функции.

Лямбда-функции находятся в C ++, так как C ++ 11. По сути, это анонимная функция, созданная на лету, которая может храниться в переменной. Вы создаете add как лямбда в main() :

auto add = [](auto x, auto y) {
return x + y;
};

Один признает лямбда по шаблону [] (list-of-arguments) {function-body};

Обратите внимание [] не всегда пусто, см. «захват переменных» там, мы вернемся к этому позже.

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

«определенное количество аргументов«Механизм разрешен вариационный шаблон аргумент Arguments... args который позволяет вызывать шаблон с любым количеством типов в качестве параметров шаблона (если они известны как время компиляции). Так что в нашем случае переданный аргумент равен 4, поэтому Arguments... args будет заменен на intи случай curry примет в качестве параметров лямбда и int,

Если мы посмотрим на код curryмы видим, что это только сама лямбда-функция, (это переменная функция, как printf()) единственная цель которого состоит в объединении аргументов, значение которых уже зафиксировано при создании экземпляра шаблона (args...) и те, чье значение передается в качестве аргументов функции карри (rest...).

Знак [=] является специальным захватить для лямбда-функции, которая позволяет использовать все локальные переменные в теле функции (здесь она позволяет использовать args).

Итак, чтобы подвести итог, вот что происходит в вашей основной функции:

  1. Вы создаете переменную с именем add который содержит лямбда
    функция
    , взять два аргумента и добавить их.
  2. Когда вы звоните curry(add,4) Вы создаете curry шаблон.
    • Первый параметр шаблона Function это тип add (лямбда принимает два int и возвращая int)
    • Второй переменный параметр содержит только один тип: тип 4т.е. int

Инстанцированный curry функция выглядит так

curry( (int,int)->(int) func, int arg){
return [=](auto... rest) {return func(arg, rest...);};
}

Обратите внимание, что вы никогда не видите эти типы из-за auto и вычет типа шаблона.

  1. Затем вы вызываете этот экземпляр с func знак равно add а также arg = 4

  2. Вы сохраняете результат этого создания в add4 который теперь лямбда принимает один параметр. Вы можете позвонить add4 с 3 в качестве аргумента (rest... 3), который затем позвонит add(4,3) и вернуться 7.

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

11

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

Других решений пока нет …