Уже есть много хороших ответов, поэтому мой ответит на часть вашего вопроса; а именно, я предпочитаю предположение вашего вопроса, поскольку ООП и функциональные возможности не являются взаимоисключающими.
Если вы используете C ++ 11, существует много таких функциональных функций программирования, встроенных в языковую / стандартную библиотеку, которые хорошо сочетаются с ООП. Конечно, я не уверен, насколько хорошо TMP будет принят вашим начальником или коллегами, но дело в том, что вы можете получить многие из этих функций в той или иной форме на нефункциональных языках / языках ООП, таких как 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;
}