Jest już wiele dobrych odpowiedzi, więc moje odniesie się do części twojego pytania; mianowicie, zastanawiam się nad założeniem twojego pytania, ponieważ OOP i funkcje nie wykluczają się wzajemnie.
Jeśli używasz C ++ 11, istnieje wiele tego rodzaju funkcji programowania funkcjonalnego wbudowanych w bibliotekę językową / standardową, które dobrze (ładnie) współdziałają z OOP. Oczywiście nie jestem pewien, jak dobrze TMP będzie odbierany przez twojego szefa lub współpracowników, ale chodzi o to, że możesz uzyskać wiele z tych funkcji w takiej czy innej formie w niefunkcjonalnych / OOP językach, takich jak C ++.
Używanie szablonów z rekurencją czasu kompilacji zależy od pierwszych 3 punktów,
- Niezmienność
- Rekurencja
- Dopasowywanie wzorów
W tym, że wartości szablonu są niezmienne (stałe czasu kompilacji), każda iteracja jest wykonywana przy użyciu rekurencji, a rozgałęzianie odbywa się przy użyciu (mniej więcej) dopasowywania wzorców, w postaci rozdzielczości przeciążenia.
Jeśli chodzi o inne punkty, użycie std::bind
i std::function
daje częściową aplikację funkcji, a wskaźniki funkcji są wbudowane w język. Obiekty wywoływalne są obiektami funkcjonalnymi (a także częściową aplikacją funkcji). Zauważ, że przez obiekty, które można wywoływać, mam na myśli te, które je definiują operator ()
.
Leniwa ocena i czyste funkcje byłyby nieco trudniejsze; dla funkcji czystych można użyć funkcji lambda, które przechwytują tylko wartości, ale nie jest to idealne.
Wreszcie, oto przykład użycia rekurencji w czasie kompilacji z aplikacją funkcji częściowej. Jest to nieco wymyślony przykład, ale pokazuje większość powyższych punktów. Rekurencyjnie powiąże wartości w danej krotce z daną funkcją i wygeneruje obiekt funkcji (na żądanie)
#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;
}