Comments 18
Не очень понимаю в чем заключается четырнадцатость/семнадцатость кода.
constexpr decltype(auto)
?
К сожалению, стоило, в противном случае мне пришлось бы писать там тип лямбды, что невозможно без decltype
и auto
, либо выносить лямбду в отдельный явный функтор, что ещё больше запутало бы. Еще как вариант там можно было бы написать std::function<int(int)>
, но это была бы совсем другая история :)
Кстати, вот предложение по variadic bind
И без меня понятно, что применять такое в реальных проектах не стоит
А вот я бы не был столь категоричен. Тут, скорее, нужно не «реальные проекты», а «коммерческие проекты, разрабатываемые командой». Во всяких вспомогательных тулах, которые тоже вполне реальны, почему бы и не использовать?
Главный минус, как это обычно бывает для тяжёлых темплейтов, во времени компиляции, даже приложенный пример компилируется как-то сильно долго…
Очень простой ответ: каррирование в исконном виде служит скорее чисто математическим целям (читать в сторону комбинаторной логики), на практике же даёт, например, возможность частичного применения, как описано в этой статье. А вот частичное применение, в свою очередь открывает путь к построению более сложных абстракций и концепций из области функционального программирования, что выливается в банальное сокращение объёмов кода при их написании. Но и без более высоких абстракций может принести пользу, там где используется всеми известный std::bind
, например, который тоже является средством частичного применения.
Похожая ситуация возникает, если мы обращаемся к вложенному типу (T::type). Ключевое слово typename помогает компилятору понять, что это тип а не статическое поле.
template <typename R, typename ... Types>
constexpr std::integral_constant<unsigned, sizeof ...(Types)> argument_cout( R(*f)(Types ...))
{
return std::integral_constant<unsigned, sizeof ...(Types)>{};
}
auto curry = [](auto func, auto ... args)
{
constexpr auto size_carry = sizeof...(args);
if constexpr (size_carry == decltype(argument_cout(func))::value)
return func(args...);
else
return [=](auto ... xs)
{
if constexpr (sizeof...(xs) + size_carry == decltype(argument_cout(func))::value)
return func(args..., xs...);
else
return curry(func, args..., xs...);
};
};
int value(int i, int f, int g)
{
return i+f+g;
}
int main() {
std::cout << curry(value,1,2,3) << std::endl;
auto v1 = curry(value);
auto v2 = v1(1);
auto v3 = v2(2);
auto v4 = v3(3);
std::cout << curry(value)(1,2)(3) + v4 << std::endl;
return 0;
}
Каррирование и частичное применение на C++14