Re: How to discover argument and result types from lambda for
constructing std::function?
On 2012-02-06 09:56, Frank Birbacher wrote:
Am 02.02.12 21:24, schrieb Daniel Kr?gler:
Some parts of your second overload look unnecessarily complicated
to me. Why shouldn't it be necessary to invoke the first overload
on function objects?
Hmm, I'm sorry I don't quite understand this question. The combination
of "why", "should not", and "is necessary" does not lead me to an
interpretation that I can make sense of.
There was a thinko in my text above. The part "Why shouldn't it be
necessary" was supposed to be "Why should it be necessary"
Consider
template<typename F> auto mkHolder(F&& f) -> typename
discover_f_type<decltype(&F::operator())>::function_type
Hmm, you mean "mkHolder" shall not construct a "Holder" object anymore,
but only a "boost::function?" This would mean the call will look like
mkHolder(mkHolder([](...){...}))
?
My ideas were badly expressed. Let me be more precise here: I suggest to
separate your problem of building an Holder object out of a lambda
expression into two clear sub-problems:
1) Generate a std::function instance out of any lambda expression (or
anything that has an unambiguous operator() overload)
2) Generate your Holder object out of a function object or out of any
thing from (1)
Let's start with (1) and can define a nice general solution for this,
e.g. (replace std::function by boost::function)
#include <functional>
#include <type_traits>
template<class F>
struct deduce_function;
template<class Ret, class C, class... Args>
struct deduce_function<Ret (C::*)(Args...) const>
{
typedef std::function<Ret(Args...)> type;
};
template<class Ret, class C, class... Args>
struct deduce_function<Ret (C::*)(Args......) const>
{
typedef std::function<Ret(Args......)> type;
};
template<class Ret, class C, class... Args>
struct deduce_function<Ret (C::*)(Args...)>
{
typedef std::function<Ret(Args...)> type;
};
template<class Ret, class C, class... Args>
struct deduce_function<Ret (C::*)(Args......)>
{
typedef std::function<Ret(Args......)> type;
};
template<class F>
typename
deduce_function<decltype(&std::remove_reference<F>::type::operator())>::type
make_function(F&& f)
{
return typename
deduce_function<decltype(&std::remove_reference<F>::type::operator())>::type(f);
}
Now given this part, we can solve sub-part (2) much more easily:
#include <utility>
template<typename Arg, typename Result>
struct Holder {
typedef std::function<Result(Arg)> Func;
Func f;
Holder(Func&& newF) : f(std::move(newF)) {}
//...
};
template<typename F>
auto mkHolder(F&& f) -> decltype(make_function(std::declval<F>()))
{
return make_function(std::forward<F>(f));
}
From a user-pointer of view your additional overload for std::function
objects is unnecessary and both make_function as well as mkHolder should
work for such objects as well. Providing such an overload makes sense,
though, because there exists a lot of freedom for libraries to add
member function signatures due to sub-clause [member.functions].
Is relying on&F::operator() fine for lambda types F?
Good question. The current wording seems to specify this quite
precisely, so it looks like a reasonable approach to me.
I wonder why there are no nested typedefs in a lambda closure type. I
expected something like in std::unary_function. Well, I can see, that
this is not a generic approach for any number of operator() argument
types, but I expected at least a typedef for something. For example
boost::function defines arg1 to argN. boost::variant defines an mpl
sequence for its types. No agreement on any typedefs for lambdas?
Lambda closures are a pure core language thingee, in contrast to
std::function and similar types from <functional>. I don't think that
adding such typedefs in the core language is worth the effort this would
have for implementations.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]