Re: [Boost-users] [Range & c++0x Lambdas] Can this be done?

I had the same issue and posted it a few months ago. I wrote to the MS VS forum that their
std::result_of should work correctly with both old and new formats; in particular use the
declared result_type if it exists (which in general lets the user override the deduced
type, great for compatibility issues).
Actually doing that robustly is a bit of a maze of metaprogramming. I ended up making a
local my_namespace::result_of that I just handles what I needed, and only when I asked for
it. That doesn't help the existing range templates, but such a change could be put back
into boost::result_of.
Meanwhile, for different reasons, I made a macro that abstracts the different syntax
between C++11 lambdas and Apple Block Closures. The latter generates a suitable lambda
class complete with result_of member. That makes me think that you could have a macro that
wraps a compiler-generated lambda expression in another class that inherits the operator()
etc. and adds in the result_of typedef to simply use decltype.
—John
Date: Wed, 21 Nov 2012 10:15:18 -0700 From: Nathan Crookston
Can the last line, labelled NOT Ok, be made to work? I think the lambda does not publish its result as a bind does, so I suspect it's hopeless. Any thoughts? // NOT Ok boost::range::push_back( out, in | transformed( []( S & s ) { return s.i; } ) ); }
It seems trivial to have a nested result_type in all cases with a lambda. However, in C++11 there's no need for it due to decltype.
Sadly, some compilers fall into a gap where result_of (boost or std) doesn't use decltype and lambdas don't publish tr1-style result_type -- leaving code like the above in the lurch.
Michel Morin wrote some code for adapting such a case which may be of interest to you: http://lists.boost.org/boost-users/2012/01/72879.php
HTH, Nate

[...rearranging...]
On Thu, Nov 22, 2012 at 6:34 AM, John M. Dlugosz
Date: Wed, 21 Nov 2012 10:15:18 -0700 From: Nathan Crookston < nathan.crookston@gmail.com> To: boost-users@lists.boost.org Subject: Re: [Boost-users] [Range & c++0x Lambdas] Can this be done? Message-ID:
Content-Type: text/plain; charset="iso-8859-1" Rob, On Wed, Nov 21, 2012 at 6:39 AM, Robert Jones wrote: Can the last line, labelled NOT Ok, be made to work? I think the lambda
does not publish its result as a bind does, so I suspect it's hopeless. Any thoughts? // NOT Ok boost::range::push_back( out, in | transformed( []( S & s ) { return s.i; } ) ); }
It seems trivial to have a nested result_type in all cases with a lambda.
However, in C++11 there's no need for it due to decltype.
Sadly, some compilers fall into a gap where result_of (boost or std) doesn't use decltype and lambdas don't publish tr1-style result_type -- leaving code like the above in the lurch.
Michel Morin wrote some code for adapting such a case which may be of interest to you: http://lists.boost.org/boost-**users/2012/01/72879.phphttp://lists.boost.org/boost-users/2012/01/72879.php
HTH, Nate
I had the same issue and posted it a few months ago. I wrote to the MS VS forum that their std::result_of should work correctly with both old and new formats; in particular use the declared result_type if it exists (which in general lets the user override the deduced type, great for compatibility issues).
Actually doing that robustly is a bit of a maze of metaprogramming. I ended up making a local my_namespace::result_of that I just handles what I needed, and only when I asked for it. That doesn't help the existing range templates, but such a change could be put back into boost::result_of.
Maybe this is what you did, so I might not be suggesting something new, but... Perhaps boost::result_of could have an extra conditional logic branch added to it: - If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) ) Meanwhile, for different reasons, I made a macro that abstracts the
different syntax between C++11 lambdas and Apple Block Closures. The latter generates a suitable lambda class complete with result_of member. That makes me think that you could have a macro that wraps a compiler-generated lambda expression in another class that inherits the operator() etc. and adds in the result_of typedef to simply use decltype.
Wouldn't that require defining a class at expression scope? Is that possible? - Jeff

All, Jeffrey Lee Hellrung, Jr. wrote:
I had the same issue and posted it a few months ago. I wrote to the MS VS
forum that their std::result_of should work correctly with both old and new formats; in particular use the declared result_type if it exists (which in general lets the user override the deduced type, great for compatibility issues).
Actually doing that robustly is a bit of a maze of metaprogramming. I ended up making a local my_namespace::result_of that I just handles what I needed, and only when I asked for it. That doesn't help the existing range templates, but such a change could be put back into boost::result_of.
Maybe this is what you did, so I might not be suggesting something new, but... Perhaps boost::result_of could have an extra conditional logic branch added to it: - If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
I like this -- it sounds like what John describes, but also using the result struct. I'd suggest that structure if neither BOOST_RESULT_OF_USE_DECLTYPE nor BOOST_RESULT_OF_USE_TR1 are defined (and BOOST_NO_DECLTYPE_N3276 is defined). Those who have been working on result_of the most lately haven't been on this thread; I'll post this with a new subject to see what they say. With or without a change to result_of, I believe there's value in allowing the user to explicitly specify the result_type of a callable object passed to transformed. Ticket #7748[1] contains a patch which permits that. Thanks, Nate [1] https://svn.boost.org/trac/boost/ticket/7748

On Wed, Nov 28, 2012 at 7:35 PM, Nathan Crookston < nathan.crookston@gmail.com> wrote: [...]
With or without a change to result_of, I believe there's value in allowing the user to explicitly specify the result_type of a callable object passed to transformed. Ticket #7748[1] contains a patch which permits that.
Thanks, Nate
I would think a preferable (in the sense of separation of concerns,
modularity, what-have-you) solution would be an addition to
Boost.Functional (or whatever) that basically wraps a callable object and
forces its result_type to be some specified template parameter. E.g.,
template< class F, class R >
struct result_binder
{
F f;
typedef R result_type;
template< class... T >
result_type operator()(T&&... x) const
{ return f(std::forward<T>(x)...); }
};
template< class R, class F >
result_binder

Jeffrey Lee Hellrung, Jr. wrote:
Nathan Crookston wrote: [...]
With or without a change to result_of, I believe there's value in allowing
the user to explicitly specify the result_type of a callable object passed to transformed. Ticket #7748[1] contains a patch which permits that.
Thanks, Nate
I would think a preferable (in the sense of separation of concerns, modularity, what-have-you) solution would be an addition to Boost.Functional (or whatever) that basically wraps a callable object and forces its result_type to be some specified template parameter. E.g.,
template< class F, class R > struct result_binder { F f; typedef R result_type; template< class... T > result_type operator()(T&&... x) const { return f(std::forward<T>(x)...); } };
template< class R, class F > result_binder
bind_result(F&& f) { return result_binder {std::forward<F>(f)}; }
I agree that such an object generator (along with Michel's make_tr1_functor) would be useful. There are two reasons why I feel extending transformed would be useful whether or not the previous object generators were added: 1. Both this and Michel's suggestions require C++11 features -- either decltype or rvalue references. Extended transformed allows the creation of a result_binder struct to be delayed until the reference type of the input range is available. This would make it usable for non-lambda instances where an explicit return type is desired without the fuss of defining a separate functor (assuming the functor to be wrapped cannot be changed). I believe a correct C++03 version of result_binder would need a large number of operator() overloads depending on how many arguments it intends to forward. 2. Such a syntax (transformed<R>(...)) has been used previously -- boost bind's docs, referring to bind<R> syntax, state: "It is generally used with function objects that do not, or cannot, expose result_type."[1] Without begging for an Emerson quote, I believe consistency with bind in this case will improve the usability enough to justify the required changes. Note also that this is the only current adaptor[2] which takes a function object with arbitrary return type (others must return something which is convertible to bool). Note also that the changes are a pure extension (previous usage continues unchanged). Thanks, Nate [1] http://www.boost.org/doc/libs/1_52_0/libs/bind/bind.html#Q_forms [2] I previously proposed a zip/unpack adaptor -- if that were adopted, unpack would be a second range object which would benefit from an explicit return type.

On Wed, Nov 28, 2012 at 9:21 PM, Nathan Crookston < nathan.crookston@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr. wrote:
Nathan Crookston wrote: [...]
With or without a change to result_of, I believe there's value in
allowing the user to explicitly specify the result_type of a callable object passed to transformed. Ticket #7748[1] contains a patch which permits that.
Thanks, Nate
I would think a preferable (in the sense of separation of concerns, modularity, what-have-you) solution would be an addition to Boost.Functional (or whatever) that basically wraps a callable object and forces its result_type to be some specified template parameter. E.g.,
template< class F, class R > struct result_binder { F f; typedef R result_type; template< class... T > result_type operator()(T&&... x) const { return f(std::forward<T>(x)...); } };
template< class R, class F > result_binder
bind_result(F&& f) { return result_binder {std::forward<F>(f)}; } I agree that such an object generator (along with Michel's make_tr1_functor) would be useful. There are two reasons why I feel extending transformed would be useful whether or not the previous object generators were added:
1. Both this and Michel's suggestions require C++11 features -- either decltype or rvalue references. Extended transformed allows the creation of a result_binder struct to be delayed until the reference type of the input range is available. This would make it usable for non-lambda instances where an explicit return type is desired without the fuss of defining a separate functor (assuming the functor to be wrapped cannot be changed). I believe a correct C++03 version of result_binder would need a large number of operator() overloads depending on how many arguments it intends to forward.
True, though this sounds like more of an implementation concern (don't get me wrong, it's a valid concern) than a capability concern. 2. Such a syntax (transformed<R>(...)) has been used previously -- boost
bind's docs, referring to bind<R> syntax, state: "It is generally used with function objects that do not, or cannot, expose result_type."[1] Without begging for an Emerson quote, I believe consistency with bind in this case will improve the usability enough to justify the required changes. Note also that this is the only current adaptor[2] which takes a function object with arbitrary return type (others must return something which is convertible to bool). Note also that the changes are a pure extension (previous usage continues unchanged).
I'm personally not swayed but it's a fair rationale nonetheless and ultimately your call since I'm not doing it :) Thanks,
Nate
[1] http://www.boost.org/doc/libs/1_52_0/libs/bind/bind.html#Q_forms [2] I previously proposed a zip/unpack adaptor -- if that were adopted, unpack would be a second range object which would benefit from an explicit return type.
- Jeff

Jeff, Jeffrey Lee Hellrung, Jr. wrote:
Nathan Crookston wrote:
1. Both this and Michel's suggestions require C++11 features -- either decltype or rvalue references. Extended transformed allows the creation of a result_binder struct to be delayed until the reference type of the input range is available. This would make it usable for non-lambda instances where an explicit return type is desired without the fuss of defining a separate functor (assuming the functor to be wrapped cannot be changed). I believe a correct C++03 version of result_binder would need a large number of operator() overloads depending on how many arguments it intends to forward.
True, though this sounds like more of an implementation concern (don't get me wrong, it's a valid concern) than a capability concern.
Agreed. I think there's also slightly more mental drag involved with a result_binder call, especially if I also need to remember where it resides to #include it. But that's minor. 2. Such a syntax (transformed<R>(...)) has been used previously -- boost
bind's docs, referring to bind<R> syntax, state: "It is generally used with function objects that do not, or cannot, expose result_type."[1] Without begging for an Emerson quote, I believe consistency with bind in this case will improve the usability enough to justify the required changes. Note also that this is the only current adaptor[2] which takes a function object with arbitrary return type (others must return something which is convertible to bool). Note also that the changes are a pure extension (previous usage continues unchanged).
I'm personally not swayed but it's a fair rationale nonetheless and ultimately your call since I'm not doing it :)
I've done all I plan to, unless a maintainer decides it's worth using and would like some changes. Just to be clear, Nathan Ridge has been proposed as a sub-maintainer, not myself. (FWIW, I think he's an excellent choice for that position.) Thanks, Nate

On Thu, Nov 29, 2012 at 12:19 AM, Nathan Crookston < nathan.crookston@gmail.com> wrote:
Jeff,
Jeffrey Lee Hellrung, Jr. wrote:
Nathan Crookston wrote:
1. Both this and Michel's suggestions require C++11 features -- either decltype or rvalue references. Extended transformed allows the creation of a result_binder struct to be delayed until the reference type of the input range is available. This would make it usable for non-lambda instances where an explicit return type is desired without the fuss of defining a separate functor (assuming the functor to be wrapped cannot be changed). I believe a correct C++03 version of result_binder would need a large number of operator() overloads depending on how many arguments it intends to forward.
True, though this sounds like more of an implementation concern (don't get me wrong, it's a valid concern) than a capability concern.
Agreed. I think there's also slightly more mental drag involved with a result_binder call, especially if I also need to remember where it resides to #include it. But that's minor.
That's a legitimate point as well.
2. Such a syntax (transformed<R>(...)) has been used previously -- boost
bind's docs, referring to bind<R> syntax, state: "It is generally used with function objects that do not, or cannot, expose result_type."[1] Without begging for an Emerson quote, I believe consistency with bind in this case will improve the usability enough to justify the required changes. Note also that this is the only current adaptor[2] which takes a function object with arbitrary return type (others must return something which is convertible to bool). Note also that the changes are a pure extension (previous usage continues unchanged).
I'm personally not swayed but it's a fair rationale nonetheless and ultimately your call since I'm not doing it :)
I've done all I plan to, unless a maintainer decides it's worth using and would like some changes. Just to be clear, Nathan Ridge has been proposed as a sub-maintainer, not myself. (FWIW, I think he's an excellent choice for that position.)
Yeah, I was confused about who was who, sorry :/ Sorry, this probably came earlier in the thread, but I suppose you have a ticket + patch lying around somewhere? Or has a Boost.Range maintainer agreed to implement these changes? - Jeff

Jeffrey Lee Hellrung, Jr. wrote:
Sorry, this probably came earlier in the thread, but I suppose you have a ticket + patch lying around somewhere? Or has a Boost.Range maintainer agreed to implement these changes?
https://svn.boost.org/trac/boost/ticket/7748 (includes patch + tests) No response from a maintainer, thus far, however. Nate

On 11/22/2012 11:31 AM, Jeffrey Lee Hellrung, Jr. wrote:
Maybe this is what you did, so I might not be suggesting something new, but... Perhaps boost::result_of could have an extra conditional logic branch added to it: - If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
C++11 defines exactly what result_of does, as did the TR1 spec before it. Making boost::result_of do something different would be surprising, IMO. If you want to use C++11 lambdas with boost::result_of, the most portable solution is with an adapter, as has been suggested elsewhere in this thread. Not ideal, but it works. -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Wed, Nov 28, 2012 at 10:26 PM, Eric Niebler
On 11/22/2012 11:31 AM, Jeffrey Lee Hellrung, Jr. wrote:
Maybe this is what you did, so I might not be suggesting something new, but... Perhaps boost::result_of could have an extra conditional logic branch added to it: - If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
C++11 defines exactly what result_of does, as did the TR1 spec before it. Making boost::result_of do something different would be surprising, IMO.
If you want to use C++11 lambdas with boost::result_of, the most portable solution is with an adapter, as has been suggested elsewhere in this thread. Not ideal, but it works.
I'm only suggesting to extend result_of for C++11 lambdas (and, incidentally, other callable types) when result_of wouldn't know what to do otherwise. Do you mean it would be surprising for result_of to work when it would be expected to fail? Maybe there's something subtle I'm missing here. I'm supposing in this, of course, that there are compilers which support lambdas and have some form of decltype sufficient for lambdas but insufficient to be the primary implementation of result_of (i.e., must use TR1-style for the primary implementation). That's quite a few compilers presently, right? - Jeff

Note: Assuming 3 categories of compiler, numbered for simplicity below. *1 No decltype *2. Partial decltype support (VC10, current g++ & earlier clang w/ std=c++0x) *3. Full decltype support (recent clang only) Jeffrey Lee Hellrung, Jr. wrote:
Eric Niebler wrote:
Jeffrey Lee Hellrung, Jr. wrote:
Maybe this is what you did, so I might not be suggesting something new, but... Perhaps boost::result_of could have an extra conditional logic branch added to it: - If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
C++11 defines exactly what result_of does, as did the TR1 spec before it. Making boost::result_of do something different would be surprising, IMO.
If you want to use C++11 lambdas with boost::result_of, the most portable solution is with an adapter, as has been suggested elsewhere in this thread. Not ideal, but it works.
I'm only suggesting to extend result_of for C++11 lambdas (and, incidentally, other callable types) when result_of wouldn't know what to do otherwise. Do you mean it would be surprising for result_of to work when it would be expected to fail? Maybe there's something subtle I'm missing here.
I'm also curious what would be surprising -- if TR1 result_of fails to deduce the result_type it causes a hard error, I believe. It may be surprising that code works on *2 but not *1; I don't see that being different than code which works on *3 not working on *2 & *1 currently. I think I was more surprised by the errors when I first tried using lambdas with boost::result_of than I would have been if it had just worked ;).
I'm supposing in this, of course, that there are compilers which support lambdas and have some form of decltype sufficient for lambdas but insufficient to be the primary implementation of result_of (i.e., must use TR1-style for the primary implementation). That's quite a few compilers presently, right?
I think if you want strictly conforming TR1 or C++11 result_of, you should define the appropriate macro -- otherwise you already get compiler-specific behavior, based on each compiler's capability. Assuming no explicit choice, I think a hybrid behavior, specific to *2, which only kicks in when TR1 result_of wouldn't cause issues where there were none before, would it? I can also see the value of implementing only TR1 and C++11 result_of -- a good deal of thought and discussion went into those documents. (As an aside, this is the second time today on this list I feel I've argued for pragmatism over purity. This is not common.) Thanks, Nate

On 11/28/2012 10:37 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Wed, Nov 28, 2012 at 10:26 PM, Eric Niebler wrote:
On 11/22/2012 11:31 AM, Jeffrey Lee Hellrung, Jr. wrote:
Maybe this is what you did, so I might not be suggesting something new, but... Perhaps boost::result_of could have an extra conditional logic branch added to it: - If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
C++11 defines exactly what result_of does, as did the TR1 spec before it. Making boost::result_of do something different would be surprising, IMO.
If you want to use C++11 lambdas with boost::result_of, the most portable solution is with an adapter, as has been suggested elsewhere in this thread. Not ideal, but it works.
I'm only suggesting to extend result_of for C++11 lambdas (and, incidentally, other callable types) when result_of wouldn't know what to do otherwise. Do you mean it would be surprising for result_of to work when it would be expected to fail? Maybe there's something subtle I'm missing here.
I'm supposing in this, of course, that there are compilers which support lambdas and have some form of decltype sufficient for lambdas but insufficient to be the primary implementation of result_of (i.e., must use TR1-style for the primary implementation). That's quite a few compilers presently, right?
Here's the surprising part:
- If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
The way I read this is that F::result_type (and F::result<>) is taking precedence over decltype. AFAICT, you're suggesting that result_of *not* compute the actual return type of a function object, but rather return the declared result type, even if it's wrong. In moving to a decltype-based result_of, we discovered just how many function objects in boost were lying about their return types via the TR1 result_of protocol. Now that we have decltype, we can get the right answer always. I would be *immensely* surprised if result_of ever got the wrong answer on a compiler that had decltype. And btw, I don't think lambdas are required to have a nested result_type typedef, are they? So what benefit does changing the protocol have? Wouldn't you still need a wrapper anyway? -- Eric Niebler BoostPro Computing http://www.boostpro.com

Eric Niebler wrote: Here's the surprising part: Jeffrey Lee Hellrung, Jr. wrote:
- If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
The way I read this is that F::result_type (and F::result<>) is taking precedence over decltype. AFAICT, you're suggesting that result_of *not* compute the actual return type of a function object, but rather return the declared result type, even if it's wrong.
In moving to a decltype-based result_of, we discovered just how many function objects in boost were lying about their return types via the TR1 result_of protocol. Now that we have decltype, we can get the right answer always. I would be *immensely* surprised if result_of ever got the wrong answer on a compiler that had decltype.
I understood the suggestion to apply when compilers had pre-3276 decltype -- so the above wouldn't apply to latest clang, nor to other compilers once they support incomplete types.
And btw, I don't think lambdas are required to have a nested result_type typedef, are they? So what benefit does changing the protocol have? Wouldn't you still need a wrapper anyway?
No, they're not required. That's the heart of the issue -- if result_of were modified (only for lacking compilers) to fall back to decltype, then the lack of result_type wouldn't require special handling by the user. Thanks, Nate

On 11/29/2012 9:29 AM, Nathan Crookston wrote:
Eric Niebler wrote:
Here's the surprising part:
Jeffrey Lee Hellrung, Jr. wrote:
- If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
The way I read this is that F::result_type (and F::result<>) is taking precedence over decltype. AFAICT, you're suggesting that result_of *not* compute the actual return type of a function object, but rather return the declared result type, even if it's wrong.
In moving to a decltype-based result_of, we discovered just how many function objects in boost were lying about their return types via the TR1 result_of protocol. Now that we have decltype, we can get the right answer always. I would be *immensely* surprised if result_of ever got the wrong answer on a compiler that had decltype.
I understood the suggestion to apply when compilers had pre-3276 decltype -- so the above wouldn't apply to latest clang, nor to other compilers once they support incomplete types.
Ah. Forgive me for having misunderstood the suggestion.
And btw, I don't think lambdas are required to have a nested result_type typedef, are they? So what benefit does changing the protocol have? Wouldn't you still need a wrapper anyway?
No, they're not required. That's the heart of the issue -- if result_of were modified (only for lacking compilers) to fall back to decltype, then the lack of result_type wouldn't require special handling by the user.
That's an interesting suggestion. (Thinking ...) It requires the ability to detect the presence or absence of a nested result<> struct template. IIRC, this is difficult, and doesn't work on all compilers. But I could be mistaken. Would you be willing to open a trac ticket and attach a patch? -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Thu, Nov 29, 2012 at 9:46 AM, Eric Niebler
On 11/29/2012 9:29 AM, Nathan Crookston wrote:
Eric Niebler wrote:
Here's the surprising part:
Jeffrey Lee Hellrung, Jr. wrote:
- If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
The way I read this is that F::result_type (and F::result<>) is taking precedence over decltype. AFAICT, you're suggesting that result_of *not* compute the actual return type of a function object, but rather return the declared result type, even if it's wrong.
In moving to a decltype-based result_of, we discovered just how many function objects in boost were lying about their return types via the TR1 result_of protocol. Now that we have decltype, we can get the right answer always. I would be *immensely* surprised if result_of ever got the wrong answer on a compiler that had decltype.
I understood the suggestion to apply when compilers had pre-3276 decltype -- so the above wouldn't apply to latest clang, nor to other compilers once they support incomplete types.
Ah. Forgive me for having misunderstood the suggestion.
And btw, I don't think lambdas are required to have a nested result_type typedef, are they? So what benefit does changing the protocol have? Wouldn't you still need a wrapper anyway?
No, they're not required. That's the heart of the issue -- if result_of were modified (only for lacking compilers) to fall back to decltype, then the lack of result_type wouldn't require special handling by the user.
That's an interesting suggestion. (Thinking ...) It requires the ability to detect the presence or absence of a nested result<> struct template.
Yes.
IIRC, this is difficult, and doesn't work on all compilers.
It's not so different from detecting the presence of result_type; hopefully compilers with lambdas and weak decltype are sufficiently sophisticated to handle it.
But I could be mistaken.
Would you be willing to open a trac ticket and attach a patch?
I can put it on the my TODO list :) - Jeff

Jeffrey Lee Hellrung, Jr. wrote:
Eric Niebler wrote:
That's an interesting suggestion. (Thinking ...) It requires the ability to detect the presence or absence of a nested result<> struct template.
Yes.
IIRC, this is difficult, and doesn't work on all compilers.
It's not so different from detecting the presence of result_type; hopefully compilers with lambdas and weak decltype are sufficiently sophisticated to handle it.
The fallback could always be predicated on BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE as well, though I suspect that's defined for all compilers with decltype.
Would you be willing to open a trac ticket and attach a patch?
I can put it on the my TODO list :)
If you don't have time for this soon, I could probably do this tonight -- if it's not stepping on your toes. . . Thanks, Nate

On Thu, Nov 29, 2012 at 10:02 AM, Nathan Crookston < nathan.crookston@gmail.com> wrote:
Jeffrey Lee Hellrung, Jr. wrote:
Eric Niebler wrote:
That's an interesting suggestion. (Thinking ...) It requires the ability to detect the presence or absence of a nested result<> struct template.
Yes.
IIRC, this is difficult, and doesn't work on all compilers.
It's not so different from detecting the presence of result_type; hopefully compilers with lambdas and weak decltype are sufficiently sophisticated to handle it.
The fallback could always be predicated on BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE as well, though I suspect that's defined for all compilers with decltype.
Would you be willing to open a trac ticket and attach a patch?
I can put it on the my TODO list :)
If you don't have time for this soon, I could probably do this tonight -- if it's not stepping on your toes. . .
Not at all, be my guest! - Jeff

On 11/29/2012 10:02 AM, Nathan Crookston wrote:
If you don't have time for this soon, I could probably do this tonight -- if it's not stepping on your toes. . .
Don't forget tests and docs. :-) -- Eric Niebler BoostPro Computing http://www.boostpro.com

All, Eric Niebler wrote:
Don't forget tests and docs. :-)
Thanks, I would have forgotten the docs. I've attempted to post the patch with the ticket[1], but it's being rejected as potential spam (due to external links in the doc changes) & the captcha isn't displayed (on chrome at least). I'll attach it here; I'd appreciate it if someone with an actual trac login could attach it for me (feel free to close 7754 as well). Please look over the patch -- all comments are welcome, particularly on improving test code coverage. Thanks, Nate [1]https://svn.boost.org/trac/boost/ticket/7753

Nathan Crookston wrote:
Eric Niebler wrote:
Don't forget tests and docs. :-)
Thanks, I would have forgotten the docs. I've attempted to post the patch with the ticket[1], but it's being rejected as potential spam (due to external links in the doc changes) & the captcha isn't displayed (on chrome at least).
I'll attach it here; I'd appreciate it if someone with an actual trac login could attach it for me (feel free to close 7754 as well).
Attached a patch by Nathan Crookston to #7753 https://svn.boost.org/trac/boost/ticket/7753 Closed #7754 as duplicate. Regards, Michel

On Thu, Nov 29, 2012 at 8:29 AM, Eric Niebler
On 11/28/2012 10:37 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Wed, Nov 28, 2012 at 10:26 PM, Eric Niebler wrote:
On 11/22/2012 11:31 AM, Jeffrey Lee Hellrung, Jr. wrote:
Maybe this is what you did, so I might not be suggesting something new, but... Perhaps boost::result_of could have an extra conditional logic branch added to it: - If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
C++11 defines exactly what result_of does, as did the TR1 spec
before
it. Making boost::result_of do something different would be surprising, IMO.
If you want to use C++11 lambdas with boost::result_of, the most portable solution is with an adapter, as has been suggested
elsewhere in
this thread. Not ideal, but it works.
I'm only suggesting to extend result_of for C++11 lambdas (and, incidentally, other callable types) when result_of wouldn't know what to do otherwise. Do you mean it would be surprising for result_of to work when it would be expected to fail? Maybe there's something subtle I'm missing here.
I'm supposing in this, of course, that there are compilers which support lambdas and have some form of decltype sufficient for lambdas but insufficient to be the primary implementation of result_of (i.e., must use TR1-style for the primary implementation). That's quite a few compilers presently, right?
Here's the surprising part:
- If F::result_type exists, return F::result_type; - Else: - If BOOST_NO_CXX11_DECLTYPE, return F::result< F ( Args... ) > - Else, if F::result<> exists, return F::result< F ( Args... ) > - Else return decltype( declval<F>() ( declval< Args >()... ) )
The way I read this is that F::result_type (and F::result<>) is taking precedence over decltype. AFAICT, you're suggesting that result_of *not* compute the actual return type of a function object, but rather return the declared result type, even if it's wrong.
In moving to a decltype-based result_of, we discovered just how many function objects in boost were lying about their return types via the TR1 result_of protocol. Now that we have decltype, we can get the right answer always. I would be *immensely* surprised if result_of ever got the wrong answer on a compiler that had decltype.
AFAIK, this is the situation we already have: many compilers have decltype but not in sufficient capacity to reliably use in the implementation of result_of. I thought you were one of the individuals spear-heading this distinction :) I think this is where we're not on the same page: I'm not proposing any changes to result_of in the event that use of decltype is enabled (either because a capable decltype is detected or via a configuration macro). Rather, I am proposing changes to result_of in the event that some form of decltype exists but result_of is still using the TR1-style protocol (i.e., using F::result_type or F::result<>). And, to reiterate, the latter situation, I had thought, was rather prevalent. And btw, I don't think lambdas are required to have a nested result_type
typedef, are they? So what benefit does changing the protocol have? Wouldn't you still need a wrapper anyway?
You would if there's no decltype whatsoever. I'm guessing there are few compilers that have lambdas but lack any form of decltype, but that's less relevant than the number of compilers that have, lambdas, have some form of decltype, but nonetheless don't use decltype in result_of. - Jeff
participants (5)
-
Eric Niebler
-
Jeffrey Lee Hellrung, Jr.
-
John M. Dlugosz
-
Michel Morin
-
Nathan Crookston