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