Using variadic template arguments to resolve a lambda signature
While there's a lot of stuff floating out there about getting the return
type of any templated callback function/method (including lambdas of
course), I'm having an extremely hard time finding information about
resolving the fully call signature of a lambda function. At least in gcc
4.7 it seems to be an edge case where the normal tricks (see below) don't
work. Here's what I'm trying to do and have so far (a stripped down
version of course)...
template<typename Sig>
struct invokable_type { };
template<typename R, typename...As>
struct invokable_type<R(As...)> {
static constexpr size_t n = sizeof...(As);
typedef R(invokable_type)(As...)
template<size_t i>
struct arg {
typedef typename peel_type<i, As...> type;
};
template<typename...As2>
static R invoke(invokable_type&& invokable, As2&&...as) {
return invokable(std::forward<As2>(as)...);
}
};
peel_type<size_t, typename...> is not included here for brevity but it's a
simple argument type peeler (I think there's one built in to C++11, but I
never bothered to look). It's unimportant for this question.
Then, of course, specializations (and further properties/typedefs) exist
for a myriad of callable types such as R(*)(As...), R(&)(As...),
(R(T::*)(As...), std::function<R(As...)>, void returns (for the sake of
invoke()), method cv qualifiers, method lvalue/rvalue qualifiers, etc,
etc, etc.
Then, somewhere down the road we have a lovely function or method
(function here, doesn't matter) that looks like...
template<typename C, typename...As>
static void do_something(C&& callback, As&&...as) {
do_something_handler<invokable_type<C>::n,
As...>::something(std::forward<C>(callback), std::forward<As>(as)...);
}
Never mind what do_something_handler does... it's entirely immaterial. The
problem lies with lambda functions.
For all possible generic invokable signatures I've specialized for (which
appears to be all but non-STL functors), this works beautifully when
do_something is called with them as the first argument (template deduction
fully works). However, lambda functions result in an uncaptured type
signature, resulting in invokable_type being used, which means things like
::n and ::args<0>::type simply don't exist.
Not-a-problem example...
void something(int x, int y) {
return x * y;
}
... and later...
do_something(something, 7, 23);
Problem example...
do_something([](int x, int y) {
return x * y;
}, 7, 23);
If I understand lambda functions correctly, the compiler is likely to
compile this lamnba to a static function within the "namespace" of the
defining scope (gcc certainly seems to). For the life of me I can't figure
out what the signature actually is though. It looks like it definitely has
one that should be deducible via template specialization (based on error
reporting).
Another tangential question is even if there is a signature I can use, how
cross-compiler dangerous this this? Are lambda compilation signatures
standardized or is it all across the board?
No comments:
Post a Comment