Уже є багато хороших відповідей, тому моя вирішить підмножину вашого питання; а саме я переймаюсь умовою вашого запитання, оскільки OOP та функціональні особливості не є взаємовиключними.
Якщо ви використовуєте C ++ 11, в мовній / стандартній бібліотеці існує багато таких функціональних функцій програмування, які добре синергують з OOP. Звичайно, я не впевнений, наскільки добре TMP буде прийнятий вашим начальником або колегами, але справа в тому, що ви можете отримати багато з цих функцій у тій чи іншій формі в нефункціональних мовах / OOP, як C ++.
Використання шаблонів з рекурсією часу компіляції покладається на ваші перші 3 бали,
- Незмінюваність
- Рекурсія
- Узгодження шаблонів
У тому, що значення шаблону є незмінними (константи часу компіляції), будь-яка ітерація робиться за допомогою рекурсії, а розгалуження здійснюється за допомогою (більш-менш) узгодження шаблону у вигляді роздільної здатності перевантаження.
Що стосується інших пунктів, то використання std::bind
та надання std::function
часткової функції застосуванню функцій та покажчиків функцій вбудовані в мову. Об'єкти, що викликаються, - це функціональні об'єкти (а також часткове застосування функції). Зауважте, що під об'єктами, що викликаються, я маю на увазі ті, що визначають їх operator ()
.
Ледача оцінка та чисті функції були б дещо складнішими; для чистих функцій можна використовувати лямбда-функції, які фіксують лише за значенням, але це не ідеально.
Нарешті, ось приклад використання рекурсії часу компіляції з частковим застосуванням функції. Це дещо надуманий приклад, але він демонструє більшість пунктів вище. Він буде рекурсивно прив'язувати значення в заданому кортежі до заданої функції та генерувати (викликається) об'єкт функції
#include <iostream>
#include <functional>
//holds a compile-time index sequence
template<std::size_t ... >
struct index_seq
{};
//builds the index_seq<...> struct with the indices (boils down to compile-time indexing)
template<std::size_t N, std::size_t ... Seq>
struct gen_indices
: gen_indices<N-1, N-1, Seq ... >
{};
template<std::size_t ... Seq>
struct gen_indices<0, Seq ... >
{
typedef index_seq<Seq ... > type;
};
template <typename RType>
struct bind_to_fcn
{
template <class Fcn, class ... Args>
std::function<RType()> fcn_bind(Fcn fcn, std::tuple<Args...> params)
{
return bindFunc(typename gen_indices<sizeof...(Args)>::type(), fcn, params);
}
template<std::size_t ... Seq, class Fcn, class ... Args>
std::function<RType()> bindFunc(index_seq<Seq...>, Fcn fcn, std::tuple<Args...> params)
{
return std::bind(fcn, std::get<Seq>(params) ...);
}
};
//some arbitrary testing function to use
double foo(int x, float y, double z)
{
return x + y + z;
}
int main(void)
{
//some tuple of parameters to use in the function call
std::tuple<int, float, double> t = std::make_tuple(1, 2.04, 0.1);
typedef double(*SumFcn)(int,float,double);
bind_to_fcn<double> binder;
auto other_fcn_obj = binder.fcn_bind<SumFcn>(foo, t);
std::cout << other_fcn_obj() << std::endl;
}