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::bind
e la std::function
funzione 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;
}