Ci sono già molte buone risposte, quindi la mia affronterà un sottoinsieme della tua domanda; vale a dire, prendo in considerazione la premessa della tua domanda, poiché OOP e le funzionalità funzionali non si escludono a vicenda.
Se usi C ++ 11, ci sono molte di queste funzionalità di programmazione funzionale integrate nella libreria linguaggio / standard che si sinergizzano (piuttosto) bene con OOP. Certo, non sono sicuro di quanto TMP verrà ricevuto dal tuo capo o dai tuoi colleghi, ma il punto è che puoi ottenere molte di queste funzionalità in un modo o nell'altro in linguaggi non funzionali / OOP, come C ++.
L'utilizzo di modelli con ricorsione in fase di compilazione si basa sui primi 3 punti,
- Immutabilità
- ricorsione
- Pattern Matching
In quel modello i valori sono immutabili (costanti del tempo di compilazione), ogni iterazione viene eseguita usando la ricorsione e la ramificazione viene eseguita usando (più o meno) la corrispondenza del modello, sotto forma di risoluzione del sovraccarico.
Per quanto riguarda gli altri punti, l'utilizzo std::binde la std::functionfunzione di applicazione parziale ti dà e i puntatori di funzione sono integrati nella lingua. Gli oggetti richiamabili sono oggetti funzionali (nonché un'applicazione con funzione parziale). Nota che per oggetti richiamabili, intendo quelli che ne definiscono operator ().
La valutazione pigra e le funzioni pure sarebbero un po 'più difficili; per funzioni pure, puoi usare funzioni lambda che catturano solo per valore, ma questo non è l'ideale.
Infine, ecco un esempio dell'utilizzo della ricorsione in fase di compilazione con l'applicazione di funzioni parziali. È un esempio un po 'inventato, ma dimostra la maggior parte dei punti sopra. Assocerà ricorsivamente i valori di una data tupla a una data funzione e genererà un oggetto funzione (richiamabile)
#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;
}