1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
#include <iostream>
#include <string>
template < typename FN_TO_BE_CALLED_LAST, typename... FNS_TO_BE_CALLED_EARLIER >
auto chain_calls( FN_TO_BE_CALLED_LAST&& fn_to_be_called_last, FNS_TO_BE_CALLED_EARLIER&&... fns_to_be_called_earlier )
{
constexpr bool there_are_no_fns_to_be_called_earlier = sizeof...(FNS_TO_BE_CALLED_EARLIER) == 0 ;
if constexpr(there_are_no_fns_to_be_called_earlier) return fn_to_be_called_last ;
else return [&] ( auto&&... args_to_be_passed_to_the_first_function_to_be_called )
// captures fn_to_be_called_last, and fns_to_be_called_earlier
{
// form the chain for function calls to be made earlier (to be made before calling fn_to_be_called_last)
const auto chained_earlier_calls = chain_calls(fns_to_be_called_earlier...) ;
// compose the complete chained call along with the args to be passed
// to the first function to be called in this chain of function calls
return fn_to_be_called_last( chained_earlier_calls(args_to_be_passed_to_the_first_function_to_be_called...) ) ;
};
// TO DO: add perfect forwarding (elided now for clarity of exposition)
}
int main()
{
const auto twice = [] ( auto i ) { return i+i ; } ;
const auto thrice = [] ( auto i ) { return i+i+i ; } ;
const auto average = [] ( double a, double b, double c, double d ) { return (a+b+c+d)/4 ; } ;
const auto twice_the_average = chain_calls( twice, average ) ;
// args_to_be_passed_to_the_first_function_to_be_called (average) == 1.9, 4.3, 9.9, 17.6
std::cout << twice_the_average( 1.9, 4.3, 9.9, 17.6 ) << '\n'
<< twice( average( 1.9, 4.3, 9.9, 17.6 ) ) << '\n' // same as above
<< "---------------\n" ;
const auto twelve_times = chain_calls( twice, thrice, twice ) ;
// args_to_be_passed_to_the_first_function_to_be_called (twice) == std::string("hello! ")
std::cout << twelve_times( std::string("hello! ") ) << '\n'
<< twice( thrice( twice( std::string("hello! ") ) ) ) << '\n' ; // same as above
}
|