I wonder why std::function
is only aware of two-argument functions. I've written some code which is working well, but there are a number of limitations. Any feedback welcome. In particular, I suspect I'm reinventing the wheel.
My code is on ideone and I will refer to it.
For example, I can describe the type of main
with:
function_type_deducer(main).describe_me();
// Output: I return i and I take 2 arguments. They are of type: i PPc
(where 'i' means 'int' and 'PPc' means pointer-to-pointer-to-char)
Standard std::function
doesn't work with functions with more than two args (see the last two lines of my code), but this code does (the sample code demonstrates three-arg functions). Maybe my design should be used in the standard library instead! I define typedef tuple<Args...> args_as_tuple;
to store all args, not just the first two argument types.
The main trick is the deduction in this function:
template<class T, class... Args>
auto function_type_deducer(T(Args...)) -> Function__<T, Args...> {
return Function__<T, Args...> {};
}
Limitations:
- It doesn't work with lambdas. This won't compile
function_type_deducer([](){}).describe_me();
- It doesn't notice that there is a small difference between
x
andy
, asy
takes astring&
, wherex
takes astring
. (std::function doesn't notice this either)
Any ideas on how to fix either of these? Have I reinvented the wheel?
It would work if
function_type_deducer
wasn't a template. :) Non-capturing lambdas (empty[]
) are implicitly convertible to function pointers. Sadly, implicit conversions aren't taken into consideration for some template argument deduction. See this question for more information (note that my answer isn't completely correct as the comments indicate).That's not a problem with the function, that's a problem with
typeid
, as this simple testcode shows:Live example on Ideone. Output:
A simple fix might be using tag dispatching:
And call
print_name<NextArg>()
instead oftypeid(NextArg).name()
.Yes, kind of and no, you didn't. Boost.Function provides typedefs for all arguments (
argN_type
style), aswell as the static constantarity
for the number thereof. However, you can't easily access those typedefs generically. You would need a roundabout way to not accidentially access non-existant ones. Thetuple
idea works best, however it can be written in a nicer way. Here's a modified version of something I once wrote:Live example on Ideone. Output:
The link to the answer with the lambda function provides the critical hint: you need to obtain a pointer to a member function for the function call operator. That is, if
T
is a function object, you need to look at&T::operator()
. With generalized SFINAE you can determine if this function call operator exists. Putting this stuff together in a possibly somewhat roundabout way, yields this (which compiles with a recent version of gcc and clang, except for the lambda function which isn't supported, yet, by clang):