
The difficulty of implementing the result_of protocol has always bothered me. I've often found myself writing a primary result<...> template and several specializations to handle different cv-qualifications, and I've still not felt that I was doing it quite right. It's lucky that operator() has to be a member function, or I'd be worried about capturing the r/lvalue-ness of the function object itself. Now I just ran into another issue, from the other side of the result_of interface. If I have a function template taking a function object argument by reference, and I want to use result_of with it, I need to do something special to account for the case where I've been passed a function reference. To wit: template <class F> typename result_of<F()>::type call(F const& f) { return f(); } int f() { return 0; } int x = call(f); The problem is that in the above case, F is deduced as int(), and we form an illegal function type (one that itself returns a function type) in result_of<F()>::type. To deal with this I need something more like template <class F> typename result_of< typename mpl::if_< is_class<F> , F , typename add_pointer<F>::type >::type() >::type call(F const& f) { return f(); } Is there an easier way? -- Dave Abrahams Boost Consulting http://boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
Now I just ran into another issue, from the other side of the result_of interface. If I have a function template taking a function object argument by reference, and I want to use result_of with it, I need to do something special to account for the case where I've been passed a function reference. To wit:
template <class F> typename result_of<F()>::type call(F const& f) { return f(); }
int f() { return 0; }
int x = call(f);
The problem is that in the above case, F is deduced as int(), and we form an illegal function type (one that itself returns a function type) in result_of<F()>::type.
Is there an easier way?
In cases like this, I've often just overloaded call(): template<typename R> R call(R(*f)()) { return f(); } If you've got function call arguments to deal with, it's not so easy, as you can end up with a lot of overloads. Anthony -- Anthony Williams | Just Software Solutions Ltd Custom Software Development | http://www.justsoftwaresolutions.co.uk Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

on Tue Apr 29 2008, Anthony Williams <anthony_w.geo-AT-yahoo.com> wrote:
David Abrahams <dave@boost-consulting.com> writes:
Now I just ran into another issue, from the other side of the result_of interface. If I have a function template taking a function object argument by reference, and I want to use result_of with it, I need to do something special to account for the case where I've been passed a function reference. To wit:
template <class F> typename result_of<F()>::type call(F const& f) { return f(); }
int f() { return 0; }
int x = call(f);
The problem is that in the above case, F is deduced as int(), and we form an illegal function type (one that itself returns a function type) in result_of<F()>::type.
Is there an easier way?
In cases like this, I've often just overloaded call():
template<typename R> R call(R(*f)()) { return f(); }
If you've got function call arguments to deal with, it's not so easy, as you can end up with a lot of overloads.
Yeah, and it doesn't work if you're really defining class templates instead of simple functions because there you won't get the usual decay to function pointer types. -- Dave Abrahams Boost Consulting http://boost-consulting.com

On Tue, Apr 29, 2008 at 5:43 AM, David Abrahams <dave@boost-consulting.com> wrote:
The difficulty of implementing the result_of protocol has always bothered me. I've often found myself writing a primary result<...> template and several specializations to handle different cv-qualifications, and I've still not felt that I was doing it quite right.
Yes, I think that's the right way to do it. My understanding is that every time you write a new overload, you need to write a new specialization of result<> for that overload, whether you're overloading on arity, type, cv-qualification, etc. You have to advertise the return type of each function definition that the compiler could choose during overload resolution; i.e there's always a one-to-one correspondence between result<> specializations and function overloads. So, there's one more regular step to take when defining a function overload - whenever you define a return type in the overload's prototype, also advertise that return type by specializing result<> for the overload. I guess this can become habitual, but like all manual processes, I can see how this poses an opportunity for human error. The result_of<> documentation doesn't address these use-cases at all, so that's no help. Maybe Egg could be of help, but it may have some usability issues of its own. Of course, the ultimate solution is the C++0x result_of that works by fiat/decltype. <snip>
template <class F> typename result_of<F()>::type call(F const& f) { return f(); }
int f() { return 0; }
int x = call(f);
The problem is that in the above case, F is deduced as int(), and we form an illegal function type (one that itself returns a function type) in result_of<F()>::type.
<snip>
Is there an easier way?
Yes, I believe so. The result_of documentation says that for a callable object f of type F you have result_of<F()>::type. So, I think one should use the exact type in situations like this. In your example above, f is a F const&, so... template <class F> typename result_of<F const&()>::type call(F const& f) { return f(); } I tried this with gcc 4.3, and it works with your example. However, I don't think this is a perfect approach for passing arbitrary callable objects. I confess I don't know all the issues off the top of my head, but I believe a better approach is to have call() accept only full-blown, first-class function objects as arguments. If users would like to pass built-in functions, they should first promote them to first-class function objects using boost::function/std::function. Of course, that opens another can of worms, if you'd like to preserve the polymorphic behavior of overloaded/templated built-ins. Daniel Walker

on Tue Apr 29 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
On Tue, Apr 29, 2008 at 5:43 AM, David Abrahams <dave@boost-consulting.com> wrote:
The difficulty of implementing the result_of protocol has always bothered me. I've often found myself writing a primary result<...> template and several specializations to handle different cv-qualifications, and I've still not felt that I was doing it quite right.
Yes, I think that's the right way to do it. My understanding is that every time you write a new overload, you need to write a new specialization of result<> for that overload, whether you're overloading on arity, type, cv-qualification, etc.
Ah, but I think you miss the point. I need the specializations to handle all the different CV-qualifications of the *function object*. I suppose if you have full control over the function object you can do it with a nested result<>, and now I forget why I might not have wanted to do that. Perhaps I just didn't want to force F to be instantiated when checking its result type.
<snip>
Is there an easier way?
Yes, I believe so. The result_of documentation says that for a callable object f of type F you have result_of<F()>::type. So, I think one should use the exact type in situations like this. In your example above, f is a F const&, so...
template <class F> typename result_of<F const&()>::type call(F const& f) { return f(); }
Fine, then take the case where call takes f by value; then F can be a function type and result_of<F()> is illegal. Because function call operators have to be member functions in C++03, an lvalue function object must behave the same as an rvalue, so result_of<T()>::type == result_of<T&()>::type is an invariant. That means I can afford to always add a reference, but it's still painful: typename result_of<typename boost::add_reference<F>::type ()>::type
I tried this with gcc 4.3, and it works with your example. However, I don't think this is a perfect approach for passing arbitrary callable objects. I confess I don't know all the issues off the top of my head, but I believe a better approach is to have call() accept only full-blown, first-class function objects as arguments. If users would like to pass built-in functions, they should first promote them to first-class function objects using boost::function/std::function.
Ouch.
Of course, that opens another can of worms, if you'd like to preserve the polymorphic behavior of overloaded/templated built-ins.
Well you can't handle that case anyway; an overload set or a template doesn't have a type that can be passed on to result_of. -- Dave Abrahams Boost Consulting http://boost-consulting.com

David Abrahams:
on Tue Apr 29 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote: ...
template <class F> typename result_of<F const&()>::type call(F const& f) { return f(); }
Fine, then take the case where call takes f by value; then F can be a function type and result_of<F()> is illegal.
If you call template <class F> typename result_of<F()>::type call( F f ) { return f(); } with a function, F will be deduced as a function pointer.

On Thu, May 1, 2008 at 3:13 PM, Peter Dimov <pdimov@pdimov.com> wrote:
David Abrahams:
on Tue Apr 29 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote: ...
template <class F> typename result_of<F const&()>::type call(F const& f) { return f(); }
Fine, then take the case where call takes f by value; then F can be a function type and result_of<F()> is illegal.
If you call
template <class F> typename result_of<F()>::type call( F f ) { return f(); }
with a function, F will be deduced as a function pointer.
Yes, and I think this is where the problem arises. In this scenario, call(f) looks like a call-by-value, but f is second-class and cannot be treated as a value. The compiler "helps" out by deducing a call by reference, actually a pointer (this comes from C, right?). So, call() requires some metaprogramming type analyses to determine whether it was passed a reference to a builtin, a reference to first-class functor, or a first-class functor value. The compiler determines which of these three occurred using function argument deduction, but result_of doesn't have access to that... well it kind of does with decltype. Regardless, call() still doesn't know what it was passed, and this could cause more trouble down the road. It seems to me it would help matters to add some constraints to the type of call()'s argument such as CopyConstructable, EqualityComparable; i.e. make it a first-class function. Daniel

On Thu, May 1, 2008 at 2:56 PM, David Abrahams <dave@boost-consulting.com> wrote:
on Tue Apr 29 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
On Tue, Apr 29, 2008 at 5:43 AM, David Abrahams <dave@boost-consulting.com> wrote:
The difficulty of implementing the result_of protocol has always bothered me. I've often found myself writing a primary result<...> template and several specializations to handle different cv-qualifications, and I've still not felt that I was doing it quite right.
Yes, I think that's the right way to do it. My understanding is that every time you write a new overload, you need to write a new specialization of result<> for that overload, whether you're overloading on arity, type, cv-qualification, etc.
Ah, but I think you miss the point. I need the specializations to handle all the different CV-qualifications of the *function object*. I suppose if you have full control over the function object you can do it with a nested result<>, and now I forget why I might not have wanted to do that. Perhaps I just didn't want to force F to be instantiated when checking its result type.
OK, I see. Actually, now that I think about it, I would revise what I wrote before. I said that you should write a result<> specialization for each overload, but that's not exactly correct. You only need to write result<> specializations for overloads that have different results. Obviously, if all the overloads have the same return type, you don't need the nested result<> at all; you can just define result_type. If the return type is argument dependent but doesn't change based on the cv-qualification of the function object, then you only need one result<> specialization for all the cv-qualification overloads. Something along the lines of the following should work fine: struct functor { template<class> struct result; template<class F, class T> struct result<F(T)> { typedef T type; }; template<class T> T operator()(T t) { return t; } template<class T> T operator()(T t) const { return t; } template<class T> T operator()(T t) volatile { return t; } }; functor f; result_of<functor(int)>::type x = f(0); const functor g = functor(); result_of<const functor(int)>::type y = g(0); volatile functor h; result_of<volatile functor(int)>::type z = h(0); Of course, if you don't have full control of the function object or you don't want to instantiate it, you can always specialize result_of directly. In fact, I know of one scenario where it's necessary to specialize result_of given the present heuristic: If a functor has argument dependent overloads for zero or more arguments, the nullary case can only be handled by specializing result_of, because the heuristic only checks result_type for nullary calls and never checks result<> if result_type is defined. This is a dark corner case where the heuristic fails horribly. However, now that the heuristic will never be codified in the standard, there's no reason not to look for better strategies on C++03 platforms.
<snip>
Is there an easier way?
Yes, I believe so. The result_of documentation says that for a callable object f of type F you have result_of<F()>::type. So, I think one should use the exact type in situations like this. In your example above, f is a F const&, so...
template <class F> typename result_of<F const&()>::type call(F const& f) { return f(); }
Fine, then take the case where call takes f by value; then F can be a function type and result_of<F()> is illegal.
Because function call operators have to be member functions in C++03, an lvalue function object must behave the same as an rvalue, so
result_of<T()>::type == result_of<T&()>::type
is an invariant. That means I can afford to always add a reference, but it's still painful:
typename result_of<typename boost::add_reference<F>::type ()>::type
But not when call() is passed a builtin function, and F is deduced as a pointer, right? So, I think that the problem occurs when passing functions as arguments, which later precipitates issues with result_of. As Peter observed a few weeks ago when Eric was dealing with similar problems, result_of can be a red herring.
I tried this with gcc 4.3, and it works with your example. However, I don't think this is a perfect approach for passing arbitrary callable objects. I confess I don't know all the issues off the top of my head, but I believe a better approach is to have call() accept only full-blown, first-class function objects as arguments. If users would like to pass built-in functions, they should first promote them to first-class function objects using boost::function/std::function.
Ouch.
Yeah, I guess that may sound a little harsh. ;-) But this constraint doesn't need to be onerous to actual end-users. With a simple level of indirection you could make the promotion transparent in most (if not all) cases. This can also be done while preserving the polymorphic behavior of both builtin function templates and function objects with templated operator(). Here's an example of a polymorphic unary call() that uses function<> to transparently promote builtin function templates to first-class. template <class F, class T> typename result_of<F(T)>::type call(F f, T t) { typedef function< typename result_of<F(T)>::type (T) > function_type; return call(function_type(f), t); } template<class T0, class T1> T0 call(function<T0(T1)> f, T1 t1) { return f(t1); } // A polymorphic builtin template<class T> int f(T) { return 0; } // A polymorphic functor struct g { typedef int result_type; template<class T> int operator()(T) { return 0; } }; // Various types struct t0 {}; struct t1 {}; int main() { // Call an unary builtin with various argument types call(f<t0>, t0()); call(f<t1>, t1()); // Call an unary functor with various argument types call(g(), t0()); call(g(), t1()); }
Of course, that opens another can of worms, if you'd like to preserve the polymorphic behavior of overloaded/templated built-ins.
Well you can't handle that case anyway; an overload set or a template doesn't have a type that can be passed on to result_of.
You can still preserve some polymorphic behavior by managing pointers to resolved overloads after the compiler has selected/generated a particular function from an overload set and/or template. I'm thinking of something along the lines of the multi-signature function that Marco uploaded to Vault last week. I'm not sure how helpful something like that would be for preserving builtin polymorphism, since the compiler is not selecting overloads based on the argument types at the call-site but based on whatever signatures you give it when the function is deferred. Unfortunately, you can defer builtin function calls, but you can't defer builtin function overload resolution. I doubt that there's a satisfying way to approximate the compiler's overload resolution in user code. But it would be cool if there were! Daniel Walker

David Abrahams wrote:
Now I just ran into another issue, from the other side of the result_of interface. If I have a function template taking a function object argument by reference, and I want to use result_of with it, I need to do something special to account for the case where I've been passed a function reference. To wit:
template <class F> typename result_of<F()>::type call(F const& f) { return f(); }
int f() { return 0; }
int x = call(f);
The problem is that in the above case, F is deduced as int(), and we form an illegal function type (one that itself returns a function type) in result_of<F()>::type.
AFAIK, there is another defect. This doesn't compile: template<class F> typename result_of<typename result_of<F()>::type()>::type call_call(F f) { return f()(); } if `f()` returns a lvalue FunctionObject.
To deal with this I need something more like
template <class F> typename result_of< typename mpl::if_< is_class<F> , F , typename add_pointer<F>::type >::type() >::type call(F const& f) { return f(); }
Is there an easier way?
How about `boost::decay`? Or an "imaginary" function `apply` might be better. template<class F> typename result_of<typeof_apply(F const &)>::type call(F const &f) { return apply(f); } Regards, -- Shunsuke Sogame

On Wed, Apr 30, 2008 at 12:04 AM, shunsuke <pstade.mb@gmail.com> wrote:
David Abrahams wrote:
To deal with this I need something more like
template <class F> typename result_of< typename mpl::if_< is_class<F> , F , typename add_pointer<F>::type >::type() >::type call(F const& f) { return f(); }
Is there an easier way?
How about `boost::decay`? Or an "imaginary" function `apply` might be better.
template<class F> typename result_of<typeof_apply(F const &)>::type call(F const &f) { return apply(f); }
Aha! That just made me realize that I didn't fully understand what Dave was getting at yesterday. call() uses call-by-reference, and since boost::result_of<> treats all references as function references, you have to somehow decompose the reference before hand to determine what to pass to result_of<> so that it will do the right thing. OK. Then the snippet I sent yesterday will work for function references but not references to function objects. Still, I think the best thing to do in this case is to make call() accept only first-class function objects by value... especially since all the tools needed to treat built-in functions or references to function objects as values will be available in C++0x as soon as you #include <functional>. For example: template <class F> typename std::result_of<const F()>::type call(const F f) { return f(); } int f() { return 0; } struct g { typedef int result_type; int operator()() const { return 0; }; }; // Promote built-in function to first-class int x = call(std::function<int()>(f)); // Call-by-reference int y = call(std::cref(g())); // Call-by-value int z = call(g()); Actually, you don't need to use function<> with the call() above since the function reference will be deduced correctly, but if call() used a concept to require AdaptableGenerator or the like, then you would have wrap the built-in in an actual functor. I believe that on modern optimizing compilers this would be as efficient as implementing call() using call-by-reference, and it's much simpler than using meta programming to analyze the reference argument. Is there a reason not to use this idiom? ... other than using references for some sort of sub-class polymorphic functors, which isn't even remotely cool. Daniel Walker

on Wed Apr 30 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
Aha! That just made me realize that I didn't fully understand what Dave was getting at yesterday. call() uses call-by-reference, and since boost::result_of<> treats all references as function references, you have to somehow decompose the reference before hand to determine what to pass to result_of<> so that it will do the right thing. OK. Then the snippet I sent yesterday will work for function references but not references to function objects. Still, I think the best thing to do in this case is to make call() accept only first-class function objects by value...
You're basically solving the problem by declaring it illegal. This issue comes up because I *want* to handle all callable types, and I expect to be able to use result_of to do it.
especially since all the tools needed to treat built-in functions or references to function objects as values will be available in C++0x as soon as you #include <functional>.
Please, don't speak to me of what's coming in 0x, at least not in the context of result_of. Presumably everything is warm, light, and golden in that mystical year of the future, and we won't need result_of. ;-) -- Dave Abrahams Boost Consulting http://boost-consulting.com

On Thu, May 1, 2008 at 3:00 PM, David Abrahams <dave@boost-consulting.com> wrote:
on Wed Apr 30 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
Aha! That just made me realize that I didn't fully understand what Dave was getting at yesterday. call() uses call-by-reference, and since boost::result_of<> treats all references as function references, you have to somehow decompose the reference before hand to determine what to pass to result_of<> so that it will do the right thing. OK. Then the snippet I sent yesterday will work for function references but not references to function objects. Still, I think the best thing to do in this case is to make call() accept only first-class function objects by value...
You're basically solving the problem by declaring it illegal. This issue comes up because I *want* to handle all callable types, and I expect to be able to use result_of to do it.
I only meant to offer a solution for the problem of passing around functions. I think result_of does handle all callable types, though the present TR1 heuristic version isn't perfect. I believe the larger problem is not how to get the return type from arbitrary callable objects but how to pass callable objects as arguments to other funtions. Isn't the simplest solution to adopt a functional programming style, which C++ allows, by treating functions as first-class objects? Actually, in functional programming languages I believe it's fairly common for all functions to be call-by-value when they are defined (I think this is the case in Lisp), though they may be invoked with references according to the environment at the call-site (similar to using ref() and cref() in C++). Obviously, C++ supports multiple programming styles, it has second-class functions, which don't act like values, and all of this is a good thing. I'm not saying that should change or be illegal. I'm just saying that a simple way to use second-class functions in a functional programming paradigm is to promote them to first-class. And a simple solution for resolving call-by-reference conflicts is to follow the example of other functional programming languages (and the C++ standard library, come to think of it), and differ the decision as to whether the functions are called by value or reference until the call site (via reference_wrapper<>). Actually, it may be possible to formalize these constraints in a set of concepts; then rather than simply being stylistic or idiomatic, the compiler could enforce them. They would be souped-up versions of SGI STL's Functors.
especially since all the tools needed to treat built-in functions or references to function objects as values will be available in C++0x as soon as you #include <functional>.
Please, don't speak to me of what's coming in 0x, at least not in the context of result_of. Presumably everything is warm, light, and golden in that mystical year of the future, and we won't need result_of. ;-)
Yes, actually, that mystical year may be 1x as there are only 19 months left until 2010. ;-) Still, I find myself using -std=c++0x all the time now, and seeing this stuff work out-of-the-box makes C++0x feel a lot more real to me, at least with respect to the library. Daniel
participants (5)
-
Anthony Williams
-
Daniel Walker
-
David Abrahams
-
Peter Dimov
-
shunsuke