What is currying?
How can currying be done in C++?
Please Explain binders in STL container?
1. What is currying?
Currying simply means a transformation of a function of several arguments to a function of a single argument. This is most easily illustrated using an example:
Take a function f that accepts three arguments:
int
f(int a,std::string b,float c)
{
// do something with a, b, and c
return 0;
}
If we want to call f, we have to provide all of its arguments f(1,"some string",19.7f).
Then a curried version of f, let's call it curried_f=curry(f) only expects a single argument, that corresponds to the first argument of f, namely the argument a. Additionally, f(1,"some string",19.7f) can also be written using the curried version as curried_f(1)("some string")(19.7f). The return value of curried_f(1) on the other hand is just another function, that handles the next argument of f. In the end, we end up with a function or callable curried_f that fulfills the following equality:
curried_f(first_arg)(second_arg)...(last_arg) == f(first_arg,second_arg,...,last_arg).
2. How can currying be achieved in C++?
The following is a little bit more complicated, but works very well for me (using c++11)... It also allows currying of arbitrary degree like so: auto curried=curry(f)(arg1)(arg2)(arg3) and later auto result=curried(arg4)(arg5). Here it goes:
#include <functional>
namespace _dtl {
template <typename FUNCTION> struct
_curry;
// specialization for functions with a single argument
template <typename R,typename T> struct
_curry<std::function<R(T)>> {
using
type = std::function<R(T)>;
const type
result;
_curry(type fun) : result(fun) {}
};
// recursive specialization for functions with more arguments
template <typename R,typename T,typename...Ts> struct
_curry<std::function<R(T,Ts...)>> {
using
remaining_type = typename _curry<std::function<R(Ts...)> >::type;
using
type = std::function<remaining_type(T)>;
const type
result;
_curry(std::function<R(T,Ts...)> fun)
: result (
[=](const T& t) {
return _curry<std::function<R(Ts...)>>(
[=](const Ts&...ts){
return fun(t, ts...);
}
).result;
}
) {}
};
}
template <typename R,typename...Ts> auto
curry(const std::function<R(Ts...)> fun)
-> typename _dtl::_curry<std::function<R(Ts...)>>::type
{
return _dtl::_curry<std::function<R(Ts...)>>(fun).result;
}
template <typename R,typename...Ts> auto
curry(R(* const fun)(Ts...))
-> typename _dtl::_curry<std::function<R(Ts...)>>::type
{
return _dtl::_curry<std::function<R(Ts...)>>(fun).result;
}
#include <iostream>
void
f(std::string a,std::string b,std::string c)
{
std::cout << a << b << c;
}
int
main() {
curry(f)("Hello ")("functional ")("world!");
return 0;
}
View output
OK, as Samer commented, I should add some explanations as to how this works. The actual implementation is done in the _dtl::_curry, while the template functions curry are only convenience wrappers. The implementation is recursive over the arguments of the std::function template argument FUNCTION.
For a function with only a single argument, the result is identical to the original function.
_curry(std::function<R(T,Ts...)> fun)
: result (
[=](const T& t) {
return _curry<std::function<R(Ts...)>>(
[=](const Ts&...ts){
return fun(t, ts...);
}
).result;
}
) {}
Here the tricky thing: For a function with more arguments, we return a lambda whose argument is bound to the first argument to the call to fun. Finally, the remaining currying for the remaining N-1 arguments is delegated to the implementation of _curry<Ts...> with one less template argument.
Update for c++14 / 17:
A new idea to approach the problem of currying just came to me... With the introduction of if constexpr into c++17 (and with the help of void_t to determine if a function is fully curried), things seem to get a lot easier:
template< class, class = std::void_t<> > struct
needs_unapply : std::true_type { };
template< class T > struct
needs_unapply<T, std::void_t<decltype(std::declval<T>()())>> : std::false_type { };
template <typename F> auto
curry(F&& f) {
/// Check if f() is a valid function call. If not we need
/// to curry at least one argument:
if constexpr (needs_unapply<decltype(f)>::value) {
return [=](auto&& x) {
return curry(
[=](auto&&...xs) -> decltype(f(x,xs...)) {
return f(x,xs...);
}
);
};
}
else {
/// If 'f()' is a valid call, just call it, we are done.
return f();
}
}
int
main()
{
auto f = [](auto a, auto b, auto c, auto d) {
return a * b * c * d;
};
return curry(f)(1)(2)(3)(4);
}
See code in action on here. With a similar approach, here is how to curry functions with arbitrary number of arguments.
The same idea seems to work out also in C++14, if we exchange the constexpr if with a template selection depending on the test needs_unapply<decltype(f)>::value:
template <typename F> auto
curry(F&& f);
template <bool> struct
curry_on;
template <> struct
curry_on<false> {
template <typename F> static auto
apply(F&& f) {
return f();
}
};
template <> struct
curry_on<true> {
template <typename F> static auto
apply(F&& f) {
return [=](auto&& x) {
return curry(
[=](auto&&...xs) -> decltype(f(x,xs...)) {
return f(x,xs...);
}
);
};
}
};
template <typename F> auto
curry(F&& f) {
return curry_on<needs_unapply<decltype(f)>::value>::template apply(f);
}
In short, currying takes a function f(x, y) and given a fixed Y, gives a new function g(x) where
g(x) == f(x, Y)
This new function may be called in situations where only one argument is supplied, and passes the call on to the original f function with the fixed Y argument.
The binders in the STL allow you to do this for C++ functions. For example:
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
// declare a binary function object
class adder: public binary_function<int, int, int> {
public:
int operator()(int x, int y) const
{
return x + y;
}
};
int main()
{
// initialise some sample data
vector<int> a, b;
a.push_back(1);
a.push_back(2);
a.push_back(3);
// here we declare a function object f and try it out
adder f;
cout << "f(2, 3) = " << f(2, 3) << endl;
// transform() expects a function with one argument, so we use
// bind2nd to make a new function based on f, that takes one
// argument and adds 5 to it
transform(a.begin(), a.end(), back_inserter(b), bind2nd(f, 5));
// output b to see what we got
cout << "b = [" << endl;
for (vector<int>::iterator i = b.begin(); i != b.end(); ++i) {
cout << " " << *i << endl;
}
cout << "]" << endl;
return 0;
}
Simplifying Gregg's example, using tr1:
#include <functional>
using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;
int f(int, int);
..
int main(){
function<int(int)> g = bind(f, _1, 5); // g(x) == f(x, 5)
function<int(int)> h = bind(f, 2, _1); // h(x) == f(2, x)
function<int(int,int)> j = bind(g, _2); // j(x,y) == g(y)
}
Tr1 functional components allow you to write rich functional-style code in C++. As well, C++0x will allow for in-line lambda functions to do this as well:
int f(int, int);
..
int main(){
auto g = [](int x){ return f(x,5); }; // g(x) == f(x, 5)
auto h = [](int x){ return f(2,x); }; // h(x) == f(2, x)
auto j = [](int x, int y){ return g(y); }; // j(x,y) == g(y)
}
And while C++ doesn't provide the rich side-effect analysis that some functional-oriented programming languages perform, const analysis and C++0x lambda syntax can help:
struct foo{
int x;
int operator()(int y) const {
x = 42; // error! const function can't modify members
}
};
..
int main(){
int x;
auto f = [](int y){ x = 42; }; // error! lambdas don't capture by default.
}
Hope that helps.
Have a look at Boost.Bind which makes the process shown by Greg more versatile:
transform(a.begin(), a.end(), back_inserter(b), bind(f, _1, 5));
This binds 5 to f's second argument.
It’s worth noting that this is not currying (instead, it’s partial application). However, using currying in a general way is hard in C++ (in fact, it only recently became possible at all) and partial application is often used instead.
Other answers nicely explain binders, so I won't repeat that part here. I will only demonstrate how currying and partial application can be done with lambdas in C++0x.
Code example: (Explanation in comments)
#include <iostream>
#include <functional>
using namespace std;
const function<int(int, int)> & simple_add =
[](int a, int b) -> int {
return a + b;
};
const function<function<int(int)>(int)> & curried_add =
[](int a) -> function<int(int)> {
return [a](int b) -> int {
return a + b;
};
};
int main() {
// Demonstrating simple_add
cout << simple_add(4, 5) << endl; // prints 9
// Demonstrating curried_add
cout << curried_add(4)(5) << endl; // prints 9
// Create a partially applied function from curried_add
const auto & add_4 = curried_add(4);
cout << add_4(5) << endl; // prints 9
}
If you're using C++14 it's very easy:
template<typename Function, typename... Arguments>
auto curry(Function function, Arguments... args) {
return [=](auto... rest) {
return function(args..., rest...);
}; // don't forget semicolumn
}
You can then use it like this:
auto add = [](auto x, auto y) { return x + y; }
// curry 4 into add
auto add4 = curry(add, 4);
add4(6); // 10
Some great answers here. I thought I would add my own because it was fun to play around with the concept.
Partial function application: The process of "binding" a function with only some of its parameters, deferring the rest to be filled in later. The result is another function with fewer parameters.
Currying: Is a special form of partial function application where you can only "bind" a single argument at a time. The result is another function with exactly 1 fewer parameter.
The code I'm about to present is partial function application from which currying is possible, but not the only possibility. It offers a few benefits over the above currying implementations (mainly because it's partial function application and not currying, heh).
Applying over an empty function:
auto sum0 = [](){return 0;};
std::cout << partial_apply(sum0)() << std::endl;
Applying multiple arguments at a time:
auto sum10 = [](int a, int b, int c, int d, int e, int f, int g, int h, int i, int j){return a+b+c+d+e+f+g+h+i+j;};
std::cout << partial_apply(sum10)(1)(1,1)(1,1,1)(1,1,1,1) << std::endl; // 10
constexpr support that allows for compile-time static_assert:
static_assert(partial_apply(sum0)() == 0);
A useful error message if you accidentally go too far in providing arguments:
auto sum1 = [](int x){ return x;};
partial_apply(sum1)(1)(1);
error: static_assert failed "Attempting to apply too many arguments!"
Other answers above return lambdas that bind an argument and then return further lambdas. This approach wraps that essential functionality into a callable object. Definitions for operator() allow the internal lambda to be called. Variadic templates allow us to check for someone going too far, and an implicit conversion function to the result type of the function call allows us to print the result or compare the object to a primitive.
Code:
namespace detail{
template<class F>
using is_zero_callable = decltype(std::declval<F>()());
template<class F>
constexpr bool is_zero_callable_v = std::experimental::is_detected_v<is_zero_callable, F>;
}
template<class F>
struct partial_apply_t
{
template<class... Args>
constexpr auto operator()(Args... args)
{
static_assert(sizeof...(args) == 0 || !is_zero_callable, "Attempting to apply too many arguments!");
auto bind_some = [=](auto... rest) -> decltype(myFun(args..., rest...))
{
return myFun(args..., rest...);
};
using bind_t = decltype(bind_some);
return partial_apply_t<bind_t>{bind_some};
}
explicit constexpr partial_apply_t(F fun) : myFun(fun){}
constexpr operator auto()
{
if constexpr (is_zero_callable)
return myFun();
else
return *this; // a callable
}
static constexpr bool is_zero_callable = detail::is_zero_callable_v<F>;
F myFun;
};
Live Demo
A few more notes:
I chose to use is_detected mainly for enjoyment and practice; it serves the same as a normal type trait would here.
There could definitely be more work done to support perfect forwarding for performance reasons
The code is C++17 because it requires for constexpr lambda support in C++17
And it seems that GCC 7.0.1 is not quite there yet, either, so I used Clang 5.0.0
Some tests:
auto sum0 = [](){return 0;};
auto sum1 = [](int x){ return x;};
auto sum2 = [](int x, int y){ return x + y;};
auto sum3 = [](int x, int y, int z){ return x + y + z; };
auto sum10 = [](int a, int b, int c, int d, int e, int f, int g, int h, int i, int j){return a+b+c+d+e+f+g+h+i+j;};
std::cout << partial_apply(sum0)() << std::endl; //0
static_assert(partial_apply(sum0)() == 0, "sum0 should return 0");
std::cout << partial_apply(sum1)(1) << std::endl; // 1
std::cout << partial_apply(sum2)(1)(1) << std::endl; // 2
std::cout << partial_apply(sum3)(1)(1)(1) << std::endl; // 3
static_assert(partial_apply(sum3)(1)(1)(1) == 3, "sum3 should return 3");
std::cout << partial_apply(sum10)(1)(1,1)(1,1,1)(1,1,1,1) << std::endl; // 10
//partial_apply(sum1)(1)(1); // fails static assert
auto partiallyApplied = partial_apply(sum3)(1)(1);
std::function<int(int)> finish_applying = partiallyApplied;
std::cout << std::boolalpha << (finish_applying(1) == 3) << std::endl; // true
auto plus2 = partial_apply(sum3)(1)(1);
std::cout << std::boolalpha << (plus2(1) == 3) << std::endl; // true
std::cout << std::boolalpha << (plus2(3) == 5) << std::endl; // true
Currying is a way of reducing a function that takes multiple arguments into a sequence of nested functions with one argument each:
full = (lambda a, b, c: (a + b + c))
print full (1, 2, 3) # print 6
# Curried style
curried = (lambda a: (lambda b: (lambda c: (a + b + c))))
print curried (1)(2)(3) # print 6
Currying is nice because you can define functions that are simply wrappers around other functions with pre-defined values, and then pass around the simplified functions. C++ STL binders provide an implementation of this in C++.
I implemented currying with variadic templates as well (see Julian's answer). However, I did not make use of recursion or std::function. Note: It uses a number of C++14 features.
The provided example (main function) actually runs at compile time, proving that the currying method does not trump essential optimizations by the compiler.
The code can be found here: https://gist.github.com/Garciat/c7e4bef299ee5c607948
with this helper file: https://gist.github.com/Garciat/cafe27d04cfdff0e891e
The code still needs (a lot of) work, which I may or may not complete soon. Either way, I'm posting this here for future reference.
Posting code in case links die (though they shouldn't):
#include <type_traits>
#include <tuple>
#include <functional>
#include <iostream>
// ---
template <typename FType>
struct function_traits;
template <typename RType, typename... ArgTypes>
struct function_traits<RType(ArgTypes...)> {
using arity = std::integral_constant<size_t, sizeof...(ArgTypes)>;
using result_type = RType;
template <size_t Index>
using arg_type = typename std::tuple_element<Index, std::tuple<ArgTypes...>>::type;
};
// ---
namespace details {
template <typename T>
struct function_type_impl
: function_type_impl<decltype(&T::operator())>
{ };
template <typename RType, typename... ArgTypes>
struct function_type_impl<RType(ArgTypes...)> {
using type = RType(ArgTypes...);
};
template <typename RType, typename... ArgTypes>
struct function_type_impl<RType(*)(ArgTypes...)> {
using type = RType(ArgTypes...);
};
template <typename RType, typename... ArgTypes>
struct function_type_impl<std::function<RType(ArgTypes...)>> {
using type = RType(ArgTypes...);
};
template <typename T, typename RType, typename... ArgTypes>
struct function_type_impl<RType(T::*)(ArgTypes...)> {
using type = RType(ArgTypes...);
};
template <typename T, typename RType, typename... ArgTypes>
struct function_type_impl<RType(T::*)(ArgTypes...) const> {
using type = RType(ArgTypes...);
};
}
template <typename T>
struct function_type
: details::function_type_impl<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
{ };
// ---
template <typename Args, typename Params>
struct apply_args;
template <typename HeadArgs, typename... Args, typename HeadParams, typename... Params>
struct apply_args<std::tuple<HeadArgs, Args...>, std::tuple<HeadParams, Params...>>
: std::enable_if<
std::is_constructible<HeadParams, HeadArgs>::value,
apply_args<std::tuple<Args...>, std::tuple<Params...>>
>::type
{ };
template <typename... Params>
struct apply_args<std::tuple<>, std::tuple<Params...>> {
using type = std::tuple<Params...>;
};
// ---
template <typename TupleType>
struct is_empty_tuple : std::false_type { };
template <>
struct is_empty_tuple<std::tuple<>> : std::true_type { };
// ----
template <typename FType, typename GivenArgs, typename RestArgs>
struct currying;
template <typename FType, typename... GivenArgs, typename... RestArgs>
struct currying<FType, std::tuple<GivenArgs...>, std::tuple<RestArgs...>> {
std::tuple<GivenArgs...> given_args;
FType func;
template <typename Func, typename... GivenArgsReal>
constexpr
currying(Func&& func, GivenArgsReal&&... args) :
given_args(std::forward<GivenArgsReal>(args)...),
func(std::move(func))
{ }
template <typename... Args>
constexpr
auto operator() (Args&&... args) const& {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CanExecute = is_empty_tuple<RestArgsPrime>;
return apply(CanExecute{}, std::make_index_sequence<sizeof...(GivenArgs)>{}, std::forward<Args>(args)...);
}
template <typename... Args>
constexpr
auto operator() (Args&&... args) && {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CanExecute = is_empty_tuple<RestArgsPrime>;
return std::move(*this).apply(CanExecute{}, std::make_index_sequence<sizeof...(GivenArgs)>{}, std::forward<Args>(args)...);
}
private:
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::false_type, std::index_sequence<Indices...>, Args&&... args) const& {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CurryType = currying<FType, std::tuple<GivenArgs..., Args...>, RestArgsPrime>;
return CurryType{ func, std::get<Indices>(given_args)..., std::forward<Args>(args)... };
}
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::false_type, std::index_sequence<Indices...>, Args&&... args) && {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CurryType = currying<FType, std::tuple<GivenArgs..., Args...>, RestArgsPrime>;
return CurryType{ std::move(func), std::get<Indices>(std::move(given_args))..., std::forward<Args>(args)... };
}
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::true_type, std::index_sequence<Indices...>, Args&&... args) const& {
return func(std::get<Indices>(given_args)..., std::forward<Args>(args)...);
}
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::true_type, std::index_sequence<Indices...>, Args&&... args) && {
return func(std::get<Indices>(std::move(given_args))..., std::forward<Args>(args)...);
}
};
// ---
template <typename FType, size_t... Indices>
constexpr
auto curry(FType&& func, std::index_sequence<Indices...>) {
using RealFType = typename function_type<FType>::type;
using FTypeTraits = function_traits<RealFType>;
using CurryType = currying<FType, std::tuple<>, std::tuple<typename FTypeTraits::template arg_type<Indices>...>>;
return CurryType{ std::move(func) };
}
template <typename FType>
constexpr
auto curry(FType&& func) {
using RealFType = typename function_type<FType>::type;
using FTypeArity = typename function_traits<RealFType>::arity;
return curry(std::move(func), std::make_index_sequence<FTypeArity::value>{});
}
// ---
int main() {
auto add = curry([](int a, int b) { return a + b; });
std::cout << add(5)(10) << std::endl;
}
These Links are relevant:
The Lambda Calculus page on Wikipedia has a clear example of currying
http://en.wikipedia.org/wiki/Lambda_calculus#Motivation
This paper treats currying in C/C++
http://asg.unige.ch/site/papers/Dami91a.pdf
C++20 provides bind_front for doing currying.
For older C++ version it can be implemented (for single argument) as follows:
template <typename TFunc, typename TArg>
class CurryT
{
private:
TFunc func;
TArg arg ;
public:
template <typename TFunc_, typename TArg_>
CurryT(TFunc_ &&func, TArg_ &&arg)
: func(std::forward<TFunc_>(func))
, arg (std::forward<TArg_ >(arg ))
{}
template <typename... TArgs>
auto operator()(TArgs &&...args) const
-> decltype( func(arg, std::forward<TArgs>(args)...) )
{ return func(arg, std::forward<TArgs>(args)...); }
};
template <typename TFunc, typename TArg>
CurryT<std::decay_t<TFunc>, std::remove_cv_t<TArg>> Curry(TFunc &&func, TArg &&arg)
{ return {std::forward<TFunc>(func), std::forward<TArg>(arg)}; }
https://coliru.stacked-crooked.com/a/82856e39da5fa50d
void Abc(std::string a, int b, int c)
{
std::cerr << a << b << c << std::endl;
}
int main()
{
std::string str = "Hey";
auto c1 = Curry(Abc, str);
std::cerr << "str: " << str << std::endl;
c1(1, 2);
auto c2 = Curry(std::move(c1), 3);
c2(4);
auto c3 = Curry(c2, 5);
c3();
}
Output:
str:
Hey12
Hey34
Hey35
If you use long chains of currying then std::shared_ptr optimization can be used to avoid copying all previous curried parameters to each new carried function.
template <typename TFunc>
class SharedFunc
{
public:
struct Tag{}; // For avoiding shadowing copy/move constructors with the
// templated constructor below which accepts any parameters.
template <typename... TArgs>
SharedFunc(Tag, TArgs &&...args)
: p_func( std::make_shared<TFunc>(std::forward<TArgs>(args)...) )
{}
template <typename... TArgs>
auto operator()(TArgs &&...args) const
-> decltype( (*p_func)(std::forward<TArgs>(args)...) )
{ return (*p_func)(std::forward<TArgs>(args)...); }
private:
std::shared_ptr<TFunc> p_func;
};
template <typename TFunc, typename TArg>
SharedFunc<
CurryT<std::decay_t<TFunc>, std::remove_cv_t<TArg>>
>
CurryShared(TFunc &&func, TArg &&arg)
{
return { {}, std::forward<TFunc>(func), std::forward<TArg>(arg) };
}
https://coliru.stacked-crooked.com/a/6e71f41e1cc5fd5c
Related
I am trying to specialize a templated function based on the arity of the lambda that I pass to it as an argument. This is what I have come up with for a solution:
template<typename Function, bool>
struct helper;
template<typename Function>
struct helper<Function, false>
{
auto operator()(Function&& func)
{
std::cout << "Called 2 argument version.\n";
return func(1, 2);
}
};
template<typename Function>
struct helper<Function, true>
{
auto operator()(Function&& func)
{
std::cout << "Called 3 argument version.\n";
return func(1, 2, 3);
}
};
template<typename T>
struct B
{
T a;
const T someVal() const { return a; }
};
template<typename Function, typename T>
auto higherOrderFun(Function&& func, const T& a)
{
return helper<Function, std::is_invocable<Function, decltype(a.someVal()), decltype(a.someVal()), decltype(a.someVal())>::value>{}(std::forward<Function>(func));
}
int main()
{
B<int> b;
std::cout << higherOrderFun([](auto x, auto y) {return x+y; }, b) << "\n";
std::cout << higherOrderFun([](auto x, auto y, auto z) {return x + y+z; }, b) << "\n";
return 0;
}
Is there a way to achieve this in a more elegant manner? I've looked through this: Arity of a generic lambda
However, the latest solution (florestan's) turns all arguments into aribtrary_t, so one has to cast them back inside of each lambda, which I do not find ideal. Ideally I would have liked to directly specialize the templated higherOrderFun with SFINAE, but as it is I use a helper class in order to achieve that. Is there a more straighforward way? For instance to apply SFINAE directly to higherOrderFun without relying on a helper class? The whole point of this is to not have to change higherOrderFun into higherOrderFun2 and higherOrderFun3, but rather have the compiler deduce the correct specialization from the lambda and the given argument (const T& a).
I should mention that I also don't care about the type of the arguments to the function - just about their count, so I would have changed decltype(a.someVal()) to auto in my example if that was possible (maybe there's a way to circumvent explicitly defining the types?).
The following template gives me the number of parameters to a lambda, a std::function, or a plain function pointer. This seems to cover all the basics. So, you specialize on n_lambda_parameters<T>::n, and plug this into your template. Depending on your specific use cases, you may need to employ the facilities offered by std::remove_reference_t or std::decay_t, to wrap this.
Tested with g++ 9. Requires std::void_t from C++17, plenty of examples of simulating std::void_t pre C++17 can be found elsewhere...
#include <functional>
// Plain function pointer.
template<typename T> struct n_func_parameters;
template<typename T, typename ...Args>
struct n_func_parameters<T(Args...)> {
static constexpr size_t n=sizeof...(Args);
};
// Helper wrapper to tease out lambda operator()'s type.
// Tease out closure's operator()...
template<typename T, typename> struct n_extract_callable_parameters;
// ... Non-mutable closure
template<typename T, typename ret, typename ...Args>
struct n_extract_callable_parameters<T, ret (T::*)(Args...) const> {
static constexpr size_t n=sizeof...(Args);
};
// ... Mutable closure
template<typename T, typename ret, typename ...Args>
struct n_extract_callable_parameters<T, ret (T::*)(Args...)> {
static constexpr size_t n=sizeof...(Args);
};
// Handle closures, SFINAE fallback to plain function pointers.
template<typename T, typename=void> struct n_lambda_parameters
: n_func_parameters<T> {};
template<typename T>
struct n_lambda_parameters<T, std::void_t<decltype(&T::operator())>>
: n_extract_callable_parameters<T, decltype(&T::operator())> {};
#include <iostream>
void foo(int, char, double=0)
{
}
int main()
{
auto closure=
[](int x, int y)
// With or without mutable, here.
{
};
std::cout << n_lambda_parameters<decltype(closure)>::n
<< std::endl; // Prints 2.
std::cout << n_lambda_parameters<decltype(foo)>::n
<< std::endl; // Prints 3.
std::cout << n_lambda_parameters<std::function<void (int)>>::n
<< std::endl; // Prints 1.
return 0;
}
I would use different overloads:
template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(std::forward<Function>(func)(1, 2, 3))
{
return std::forward<Function>(func)(1, 2, 3);
}
template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(std::forward<Function>(func)(1, 2))
{
return std::forward<Function>(func)(1, 2);
}
Possibly with overload priority as
struct low_priority {};
struct high_priority : low_priority{};
template<typename Function>
auto higherOrderFunImpl(Function&& func, low_priority)
-> decltype(std::forward<Function>(func)(1, 2))
{
return std::forward<Function>(func)(1, 2);
}
template<typename Function>
auto higherOrderFunImpl(Function&& func, high_priority)
-> decltype(std::forward<Function>(func)(1, 2))
{
return std::forward<Function>(func)(1, 2);
}
template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(higherOrderFun(std::forward<Function>(func), high_priority{}))
{
return higherOrderFun(std::forward<Function>(func), high_priority{});
}
If you want to use the arity traits from florestan, it might result in:
template<typename F>
decltype(auto) higherOrderFun(F&& func)
{
if constexpr (arity_v<std::decay_t<F>, MaxArity> == 3)
{
return std::forward<F>(func)(1, 2, 3);
}
else if constexpr (arity_v<std::decay_t<F>, MaxArity> == 2)
{
return std::forward<F>(func)(1, 2);
}
// ...
}
Problem description:
C++17 introduces std::invocable<F, Args...>, which is nice to detect if a type... is invocable with the given arguments. However, would there be a way to do it for any arguments for functors (because combinations of the existing traits of the standard library already allow to detect functions, function pointers, function references, member functions...)?
In other words, how to implement the following type trait?
template <class F>
struct is_functor {
static constexpr bool value = /*using F::operator() in derived class works*/;
};
Example of use:
#include <iostream>
#include <type_traits>
struct class0 {
void f();
void g();
};
struct class1 {
void f();
void g();
void operator()(int);
};
struct class2 {
void operator()(int);
void operator()(double);
void operator()(double, double) const noexcept;
};
struct class3 {
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
union union0 {
unsigned int x;
unsigned long long int y;
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
struct final_class final {
template <class... Args> constexpr int operator()(Args&&...);
template <class... Args> constexpr int operator()(Args&&...) const;
};
int main(int argc, char* argv[]) {
std::cout << is_functor<int>::value;
std::cout << is_functor<class0>::value;
std::cout << is_functor<class1>::value;
std::cout << is_functor<class2>::value;
std::cout << is_functor<class3>::value;
std::cout << is_functor<union0>::value;
std::cout << is_functor<final_class>::value << std::endl;
return 0;
}
should output 001111X. In an ideal world, X should be 1, but I don't think it's doable in C++17 (see bonus section).
Edit:
This post seems to present a strategy that solves the problem. However, would there be a better/more elegant way to do it in C++17?
Bonus:
And as a bonus, would there be a way to make it work on final types (but that's completely optional and probably not doable)?
Building on my answer to my answer to this qustion, i was able to solve your problem, including the bonus one :-)
The following is the code posted in the other thread plus some little tweaks to get a special value when an object can't be called. The code needs c++17, so currently no MSVC...
#include<utility>
constexpr size_t max_arity = 10;
struct variadic_t
{
};
struct not_callable_t
{
};
namespace detail
{
// it is templated, to be able to create a
// "sequence" of arbitrary_t's of given size and
// hece, to 'simulate' an arbitrary function signature.
template <size_t>
struct arbitrary_t
{
// this type casts implicitly to anything,
// thus, it can represent an arbitrary type.
template <typename T>
operator T&& ();
template <typename T>
operator T& ();
};
template <typename F, size_t... Is,
typename U = decltype(std::declval<F>()(arbitrary_t<Is>{}...))>
constexpr auto test_signature(std::index_sequence<Is...>)
{
return std::integral_constant<size_t, sizeof...(Is)>{};
}
template <size_t I, typename F>
constexpr auto arity_impl(int) -> decltype(test_signature<F>(std::make_index_sequence<I>{}))
{
return {};
}
template <size_t I, typename F, std::enable_if_t<(I == 0), int> = 0>
constexpr auto arity_impl(...) {
return not_callable_t{};
}
template <size_t I, typename F, std::enable_if_t<(I > 0), int> = 0>
constexpr auto arity_impl(...)
{
// try the int overload which will only work,
// if F takes I-1 arguments. Otherwise this
// overload will be selected and we'll try it
// with one element less.
return arity_impl<I - 1, F>(0);
}
template <typename F, size_t MaxArity = 10>
constexpr auto arity_impl()
{
// start checking function signatures with max_arity + 1 elements
constexpr auto tmp = arity_impl<MaxArity + 1, F>(0);
if constexpr(std::is_same_v<std::decay_t<decltype(tmp)>, not_callable_t>) {
return not_callable_t{};
}
else if constexpr (tmp == MaxArity + 1)
{
// if that works, F is considered variadic
return variadic_t{};
}
else
{
// if not, tmp will be the correct arity of F
return tmp;
}
}
}
template <typename F, size_t MaxArity = max_arity>
constexpr auto arity(F&& f) { return detail::arity_impl<std::decay_t<F>, MaxArity>(); }
template <typename F, size_t MaxArity = max_arity>
constexpr auto arity_v = detail::arity_impl<std::decay_t<F>, MaxArity>();
template <typename F, size_t MaxArity = max_arity>
constexpr bool is_variadic_v = std::is_same_v<std::decay_t<decltype(arity_v<F, MaxArity>)>, variadic_t>;
// HERE'S THE IS_FUNCTOR
template<typename T>
constexpr bool is_functor_v = !std::is_same_v<std::decay_t<decltype(arity_v<T>)>, not_callable_t>;
Given the classes in yout question, the following compiles sucessfully (you can even use variadic lambdas:
constexpr auto lambda_func = [](auto...){};
void test_is_functor() {
static_assert(!is_functor_v<int>);
static_assert(!is_functor_v<class0>);
static_assert(is_functor_v<class1>);
static_assert(is_functor_v<class2>);
static_assert(is_functor_v<class3>);
static_assert(is_functor_v<union0>);
static_assert(is_functor_v<final_class>);
static_assert(is_functor_v<decltype(lambda_func)>);
}
See also a running example here.
I'm trying to create a generic wrapper function that takes a function as a template argument and takes the same arguments as that function as its arguments. For example:
template <typename F, F func>
/* return type of F */ wrapper(Ts... Args /* not sure how to get Ts*/)
{
// do stuff
auto ret = F(std::forward<Ts>(args)...);
// do some other stuff
return ret;
}
The solution needs to be castable to a function pointer with the same type as func so that I can pass it to a C api. In other words, the solution needs to be a function and not a function object. Most importantly, I need to be able to do work in the wrapper function.
If the inline comments aren't clear, I'd like to be able to do something like the following:
struct c_api_interface {
int (*func_a)(int, int);
int (*func_b)(char, char, char);
};
int foo(int a, int b)
{
return a + b;
}
int bar(char a, char b, char c)
{
return a + b * c;
}
c_api_interface my_interface;
my_interface.func_a = wrapper<foo>;
my_interface.func_b = wrapper<bar>;
I looked for related posts and found these, but none of them are quite what I'm trying to do. Most of these posts concern function objects. Is what I'm trying to do even possible?
Function passed as template argument
Function wrapper via (function object) class (variadic) template
How does wrapping a function pointer and function object work in generic code?
How do I get the argument types of a function pointer in a variadic template class?
Generic functor for functions with any argument list
C++ Functors - and their uses
In response to the first 2 responses, I edited the question to make it clear that I need to be able to do work in the wrapper function (i.e. modify some global state before and after the call to the wrapped function)
template<class F, F f> struct wrapper_impl;
template<class R, class... Args, R(*f)(Args...)>
struct wrapper_impl<R(*)(Args...), f> {
static R wrap(Args... args) {
// stuff
return f(args...);
}
};
template<class F, F f>
constexpr auto wrapper = wrapper_impl<F, f>::wrap;
Use as wrapper<decltype(&foo), foo>.
#include <utility>
#include <iostream>
struct c_api_interface { int (*func_a)(int, int); int (*func_b)(char, char, char); };
int foo(int a, int b) { return a + b; }
int bar(char a, char b, char c) { return a + b * c; }
template<typename Fn, Fn fn, typename... Args>
typename std::result_of<Fn(Args...)>::type
wrapper(Args... args) {
std::cout << "and ....it's a wrap ";
return fn(std::forward<Args>(args)...);
}
#define WRAPIT(FUNC) wrapper<decltype(&FUNC), &FUNC>
int main() {
c_api_interface my_interface;
my_interface.func_a = WRAPIT(foo);
my_interface.func_b = WRAPIT(bar);
std:: cout << my_interface.func_a(1,1) << std::endl;
std:: cout << my_interface.func_b('a','b', 1) << std::endl;
return 0;
}
see http://rextester.com/ZZD18334
you may try something like that (Ugly, but works)
#include <iostream>
#include <functional>
struct wrapper_ctx
{
wrapper_ctx ()
{
std::cout << "Before" << std::endl;
}
~wrapper_ctx ()
{
std::cout << "after" << std::endl;
}
};
template <typename F, typename... Args>
auto executor (F&& f, Args&&... args) -> typename std::result_of<F(Args...)>::type
{
wrapper_ctx ctx;
return std::forward<F>(f)( std::forward<Args>(args)...);
}
template <typename F>
class wrapper_helper;
template<typename Ret, typename... Args>
class wrapper_helper <std::function<Ret(Args...)>>
{
std::function<Ret(Args...)> m_f;
public:
wrapper_helper( std::function<Ret(Args...)> f )
: m_f(f) {}
Ret operator()(Args... args) const
{
return executor (m_f, args...);
}
};
template <typename T>
wrapper_helper<T> wrapper (T f)
{
return wrapper_helper <T>(f);
}
int sum(int x, int y)
{
return x + y;
}
int main (int argc, char* argv [])
{
std::function<int(int, int)> f = sum;
auto w = wrapper (f);
std::cout << "Executing the wrapper" << std::endl;
int z = w(3, 4);
std::cout << "z = " << z << std::endl;
}
you probably need something like
template <typename F>
class Wrapper {
public:
Wrapper(F *func) : function(func) {}
operator F* () { return function; }
F *function;
};
Which you can use like void (*funcPtr)(int) = Wrapper<void(int)>(&someFunction);
I think that will be the concise way to do what you want:
template <typename F>
F* wrapper(F* pFunc)
{
return pFunc;
}
and use it like this:
my_interface.func_a = wrapper(foo);
my_interface.func_a(1, 3);
You may try this
template <class R, class... Args>
struct wrap
{
using funct_type = R(*)(Args...);
funct_type func;
wrap(funct_type f): func(f) {};
R operator()(Args&&... args)
{
//before code block
std::cout << "before calling\n";
R ret=func(std::forward<Args>(args)...);
//after code block
std::cout << "After calling\n";
}
};
use like this for example:
int somefunc(double &f, int x);
auto wrapped_somefunc=wrap{somefunc};
double f=1.0;
int x = 2;
auto result=wrapped_somefunc(f,x);
This one is for c++17 and newer uses auto template parameters:
template <auto func, class... Args>
auto wrap_func(Args... args)
{
std::cout << "before calling wrapped func\n";
auto ret = func(args...);
std::cout << "after calling wrapped func\n";
return ret;
}
use for example:
int some_func(int a, int b);
auto ret = wrap_func<some_func>(2, 3);
I'm trying to implement a generic curry function in C++14 that takes a callable object as an input parameter and allows currying.
Desired syntax:
auto sum3 = [](int x, int y, int z){ return x + y + z; };
int main()
{
assert(curry(sum3)(1)(1)(1) == 3);
auto plus2 = curry(sum3)(1)(1);
assert(plus2(1) == 3);
assert(plus2(3) == 5);
}
My implementation idea is as follows: have the curry function return an unary function that binds its argument to a future call to the original function, recursively. Call the bound original function on the "last recursive step".
Detecting the "last recursive step" is the problematic part.
My idea was detecting whether or not the current bound function (during the recursion) was legally callable with zero arguments, using a is_zero_callable type trait:
template <typename...>
using void_t = void;
template <typename, typename = void>
class is_zero_callable : public std::false_type
{
};
template <typename T>
class is_zero_callable<T, void_t<decltype(std::declval<T>()())>>
: public std::true_type
{
};
Unfortunately, I cannot seem to find a way to check the correct function for zero-argument "callability" - I need to somehow check if the function that will be returned from the currently bound function is zero-callable.
Here's what I've got so far (godbolt link):
template <typename TF, bool TLastStep>
struct curry_impl;
// Base case (last step).
// `f` is a function callable with no arguments.
// Call it and return.
template <typename TF>
struct curry_impl<TF, true>
{
static auto exec(TF f)
{
return f();
}
};
// Recursive case.
template <typename TF, bool TLastStep>
struct curry_impl
{
static auto exec(TF f)
{
// Bind `x` to subsequent calls.
return [=](auto x)
{
// This is `f`, with `x` bound as the first argument.
// (`f` is the original function only on the first recursive
// step.)
auto bound_f = [=](auto... xs)
{
return f(x, xs...);
};
// Problem: how to detect if we need to stop the recursion?
using last_step = std::integral_constant<bool, /* ??? */>;
// `is_zero_callable<decltype(bound_f)>{}` will not work,
// because `bound_f` is variadic and always zero-callable.
// Curry recursively.
return curry_impl<decltype(bound_f),
last_step{}>::exec(bound_f);
};
}
};
// Interface function.
template <typename TF>
auto curry(TF f)
{
return curry_impl<TF, is_zero_callable<decltype(f)>{}>::exec(f);
}
Is my approach/intuition viable? (Is it actually possible to stop the recursion by detecting whether or not we've reached a zero-arg-callable version of the original function?)
...or is there a better way of solving this problem?
(Please ignore the missing perfect forwarding and the lack of polish in the example code.)
(Note that I've tested this currying implementation using an user-specified template int TArity parameter to stop the recursion, and it worked properly. Having the user manually specify the arity of the original f function is unacceptable, however.)
The minimal changes required to make this work in Clang is
auto bound_f = [=](auto... xs) -> decltype(f(x, xs...))
// ^^^^^^^^^^^^^^^^^^^^^^^^^
{
return f(x, xs...);
};
using last_step = std::integral_constant<bool,
is_zero_callable<decltype(bound_f)>{}>;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Explicitly specifying the return type should make it SFINAE-friendly and capable of being detected by is_zero_callable. Unfortunately, GCC is unhappy with this, probably due to a bug.
A generic lambda is basically a class with a templated operator(), so we can just write it ourselves:
template<class F, class T>
struct bound_function {
F f;
T arg;
template<class... Args>
auto operator()(Args... args) const -> decltype(f(arg, args...)){
return f(arg, args...);
}
};
Note that I'm imitating the semantics of the generic lambda here and making the operator() const. A full-featured implementation will likely want to overload on constness and value categories.
Then
auto bound_f = bound_function<TF, decltype(x)>{f, x};
works in both GCC and Clang, but has a theoretical problem: when only f(arg) is valid (and not with extra arguments), then instantiating bound_function (which instantiates a declaration of its operator()) is ill-formed NDR because every valid specialization of operator()'s declaration requires an empty parameter pack.
To avoid this, let's specialize bound_function for the "no further arguments needed" case. And since we are computing this information anyway, let's just express it in a member typedef.
template<class F, class T, class = void>
struct bound_function {
using zero_callable = std::false_type;
F f;
T arg;
template<class... Args>
auto operator()(Args... args) const -> decltype(f(arg, args...)){
return f(arg, args...);
}
};
template<class F, class T>
struct bound_function<F, T, void_t<decltype(std::declval<const F&>()(std::declval<const T&>()))>> {
using zero_callable = std::true_type;
F f;
T arg;
decltype(auto) operator()() const {
return f(arg);
}
};
Then
auto bound_f = bound_function<TF, decltype(x)>{f, x};
using last_step = typename decltype(bound_f)::zero_callable;
under file check. please.
https://github.com/sim9108/Study2/blob/master/SDKs/curryFunction.cpp
// ConsoleApplication4.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <functional>
#include <type_traits>
// core function
template<typename FN, std::size_t N>
struct curry
{
FN fn_;
curry(FN fn) :fn_{ fn }
{
}
template<typename... TS, typename = std::enable_if_t< (N - sizeof...(TS)) != 0, int >>
auto operator()(TS... ts1) {
auto fn = [f = this->fn_, ts1...](auto... args) mutable {
return f(ts1..., args...);
};
return curry<decltype(fn), N - sizeof...(TS)>(fn);
}
template<typename... TS, typename Z = void, typename = std::enable_if_t< (N - sizeof...(TS)) == 0, int > >
auto operator()(TS... ts1) {
return fn_(ts1...);
}
};
//general make curry function
template<typename R, typename... Args>
auto make_curry(R(&f)(Args...)) {
auto fn = [&f](Args... args) {
return f(args...);
};
return curry<decltype(fn), sizeof...(Args)>(fn);
}
//general make curry member function
template<typename C, typename R, typename... Args>
auto make_curry(R(C::*f)(Args...), C c) {
auto fn = [f, c](Args... args) mutable {
return (c.*f)(args...);
};
return curry<decltype(fn), sizeof...(Args)>(fn);
}
template<typename C, typename R, typename... Args>
auto make_curry(R(C::*f)(Args...) const, C c) {
auto fn = [f, c](Args... args) mutable {
return (c.*f)(args...);
};
return curry<decltype(fn), sizeof...(Args)>(fn);
}
//general make curry lambda function
template<typename C>
auto make_curry(C&& c) {
using CR = std::remove_reference_t<C>;
return make_curry(&CR::operator(), c);
}
using std::string;
using std::function;
string func(string a, string b, string c) {
return "general function:" + a + b + c;
}
struct A {
string func(string a, string b, string c) {
return "member function:" + a + b + c;
};
};
int main(int argc, char* argv[])
{
{ //general function curry
auto c = make_curry(func);
auto m1 = c("t1")("t2")("t3");
auto m2 = c("test1")("test2")("test3");
auto m3 = c("m1");
auto m4 = m3("m2");
auto m5 = m4("m3");
std::cout << m5 << std::endl;
std::cout << m2 << std::endl;
std::cout << m5 << std::endl;
}
{ //member function curry
A a;
auto c = make_curry(&A::func, a);
auto m1 = c("t1")("t2")("t3");
auto m2 = c("test1")("test2")("test3");
auto m3 = c("m1");
auto m4 = m3("m2");
auto m5 = m4("m3");
std::cout << m1 << std::endl;
std::cout << m2 << std::endl;
std::cout << m5 << std::endl;
}
{ //lambda function curry
auto fn = [](string a, string b, string c) {
return "lambda function:" + a + b + c;
};
auto c = make_curry(fn);
auto m1 = c("t1")("t2")("t3");
auto m2 = c("test1")("test2")("test3");
auto m3 = c("m1");
auto m4 = m3("m2");
auto m5 = m4("m3");
std::cout << m1 << std::endl;
std::cout << m2 << std::endl;
std::cout << m5 << std::endl;
}
auto func3 = make_curry(func);
std::cout << func3("Hello, ")( "World!", " !hi") << std::endl;
std::cout << func3("Hello, ","World!")(" !hi") << std::endl;
std::cout << func3("Hello, ","World!", " !hi") << std::endl;
std::cout << func3()("Hello, ", "World!", " !hi") << std::endl;
return 0;
}
I'm trying to create a function which can be called with a lambda that takes either 0, 1 or 2 arguments. Since I need the code to work on both g++ 4.5 and vs2010(which doesn't support variadic templates or lambda conversions to function pointers) the only idea I've come up with is to choose which implementation to call based on arity. The below is my non working guess at how this should look. Is there any way to fix my code or is there a better way to do this in general?
#include <iostream>
#include <functional>
using namespace std;
template <class Func> struct arity;
template <class Func>
struct arity<Func()>{ static const int val = 0; };
template <class Func, class Arg1>
struct arity<Func(Arg1)>{ static const int val = 1; };
template <class Func, class Arg1, class Arg2>
struct arity<Func(Arg1,Arg2)>{ static const int val = 2; };
template<class F>
void bar(F f)
{
cout << arity<F>::val << endl;
}
int main()
{
bar([]{cout << "test" << endl;});
}
A lambda function is a class type with a single function call operator. You can thus detect the arity of that function call operator by taking its address and using overload resolution to select which function to call:
#include <iostream>
template<typename F,typename R>
void do_stuff(F& f,R (F::*mf)() const)
{
(f.*mf)();
}
template<typename F,typename R,typename A1>
void do_stuff(F& f,R (F::*mf)(A1) const)
{
(f.*mf)(99);
}
template<typename F,typename R,typename A1,typename A2>
void do_stuff(F& f,R (F::*mf)(A1,A2) const)
{
(f.*mf)(42,123);
}
template<typename F>
void do_stuff(F f)
{
do_stuff(f,&F::operator());
}
int main()
{
do_stuff([]{std::cout<<"no args"<<std::endl;});
do_stuff([](int a1){std::cout<<"1 args="<<a1<<std::endl;});
do_stuff([](int a1,int a2){std::cout<<"2 args="<<a1<<","<<a2<<std::endl;});
}
Be careful though: this won't work with function types, or class types that have more than one function call operator, or non-const function call operators.
I thought the following would work but it doesn't, I'm posting it for two reasons.
To save people the time if they had the same idea
If someone knows why this doesn't work, I'm not 100% sure I understand (although I have my suspicions)
Code follows:
#include <iostream>
#include <functional>
template <typename Ret>
unsigned arity(std::function<Ret()>) { return 0; }
template <typename Ret, typename A1>
unsigned arity(std::function<Ret(A1)>) { return 1; }
template <typename Ret, typename A1, typename A2>
unsigned arity(std::function<Ret(A1, A2)>) { return 2; }
// rinse and repeat
int main()
{
std::function<void(int)> f = [](int i) { }; // this binds fine
// Error: no matching function for call to 'arity(main()::<lambda(int)>)'
std::cout << arity([](int i) { });
}
Compile time means of obtaining the arity of a function or a function object, including that of a lambda:
int main (int argc, char ** argv) {
auto f0 = []() {};
auto f1 = [](int) {};
auto f2 = [](int, void *) {};
std::cout << Arity<decltype(f0)>::value << std::endl; // 0
std::cout << Arity<decltype(f1)>::value << std::endl; // 1
std::cout << Arity<decltype(f2)>::value << std::endl; // 2
std::cout << Arity<decltype(main)>::value << std::endl; // 2
}
template <typename Func>
class Arity {
private:
struct Any {
template <typename T>
operator T ();
};
template <typename T>
struct Id {
typedef T type;
};
template <size_t N>
struct Size {
enum { value = N };
};
template <typename F>
static Size<0> match (
F f,
decltype(f()) * = nullptr);
template <typename F>
static Size<1> match (
F f,
decltype(f(Any())) * = nullptr,
decltype(f(Any())) * = nullptr);
template <typename F>
static Size<2> match (
F f,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr);
public:
enum { value = Id<decltype(match(static_cast<Func>(Any())))>::type::value };
};
This way works:
template<typename F>
auto call(F f) -> decltype(f(1))
{
return f(1);
}
template<typename F>
auto call(F f, void * fake = 0) -> decltype(f(2,3))
{
return f(2,3);
}
template<typename F>
auto call(F f, void * fake = 0, void * fake2 = 0) -> decltype(f(4,5,6))
{
return f(4,5,6);
}
int main()
{
auto x1 = call([](int a){ return a*10; });
auto x2 = call([](int a, int b){ return a*b; });
auto x3 = call([](int a, int b, int c){ return a*b*c; });
// x1 == 1*10
// x2 == 2*3
// x3 == 4*5*6
}
It works for all callable types (lambdas, functors, etc)