[Boost-users] [range] cannot use lambda predicate in adaptor with certain algorithms

70 views
Skip to first unread message

Nathan Ridge

unread,
May 30, 2011, 4:12:35 AM5/30/11
to Boost Mailing List

Hello,

I get errors related to lambdas not being default-constructible or copy-assignable
when using a lambda as a predicate with certain adaptors (e.g. filtered) and
certain algorithms (e.g. min_element).

The following code illustrates the problem:

#include <boost/range/algorithm/min_element.hpp>
#include <boost/range/adaptor/filtered.hpp>
int main()
{
int a[] = {1, 2, 3};
auto is_odd = [](int i){ return i % 2 == 1; };
boost::min_element(a | boost::adaptors::filtered(is_odd));
}

The errors are shown below.

Is there a workaround for this?

Thanks,
Nate.

Errors:

In file included from algorithm:63:0,
from /usr/lib/boost/boost/iterator/iterator_concepts.hpp:29,
from /usr/lib/boost/boost/range/concepts.hpp:20,
from /usr/lib/boost/boost/range/algorithm/min_element.hpp:15,
from test.cpp:1:
stl_algo.h: In function 'boost::filter_iterator<main()::<lambda(int)>, int *>
min_element(
boost::filter_iterator<main()::<lambda(int)>, int *>
, boost::filter_iterator<main()::<lambda(int)>, int *>
)':
/usr/lib/boost/boost/range/algorithm/min_element.hpp:44:63:
instantiated from 'boost::range_iterator<const T>::ame boost
::range_iterator<const T>::type = boost::filter_iterator<
main()::<lambda(int)>, int *
> boost::range::min_element(
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
> &
)'
test.cpp:8:61: instantiated from here
stl_algo.h:6109:4: error: use of deleted function 'boost::filter_iterator<
main()::<lambda(int)>, int *
> & boost::filter_iterator<main()::<lambda(int)>, int *>::operator=(
const boost::filter_iterator<main()::<lambda(int)>, int *> &
)'
In file included from /usr/lib/boost/boost/range/adaptor/filtered.hpp
:16:0,
from test.cpp:2:
/usr/lib/boost/boost/iterator/filter_iterator.hpp:44:9: error: 'boost
::filter_iterator<main()::<lambda(int)>, int *> & boost::filter_iterator<
main()::<lambda(int)>, int *
>::operator=(
const boost::filter_iterator<main()::<lambda(int)>, int *> &
)' is implicitly deleted because the default definition would be ill-
formed:
/usr/lib/boost/boost/iterator/filter_iterator.hpp:44:9: error: use of
deleted function 'main()::<lambda(int)> & main()::<lambda(int)>::operator=(
const main()::<lambda(int)> &
)'
test.cpp:7:20: error: a lambda closure type has a deleted copy assignment
operator
In file included from /usr/lib/boost/boost/range/adaptor/filtered.hpp
:16:0,
from test.cpp:2:
/usr/lib/boost/boost/iterator/filter_iterator.hpp: In constructor
'boost::filter_iterator<main()::<lambda(int)>, int *>::filter_iterator()':
/usr/lib/boost/boost/concept_check.hpp:133:10: instantiated from
'boost::DefaultConstructible<
boost::filter_iterator<main()::<lambda(int)>, int *>
>::~DefaultConstructible()'
/usr/lib/boost/boost/concept/usage.hpp:22:29: instantiated from
'boost::concepts::usage_requirements<
boost::DefaultConstructible<
boost::filter_iterator<main()::<lambda(int)>, int *>
>
>::~usage_requirements()'
/usr/lib/boost/boost/concept/detail/general.hpp:38:28: instantiated
from 'static void boost::concepts::requirement<
boost::concepts::failed ************ boost::concepts
::usage_requirements<
boost::DefaultConstructible<
boost::filter_iterator<main()::<lambda(int)>, int *>
>
>::************
>::failed()'
/usr/lib/boost/boost/concept_check.hpp:132:1: instantiated from
'boost::DefaultConstructible<
boost::filter_iterator<main()::<lambda(int)>, int *>
>'
/usr/lib/boost/boost/range/concepts.hpp:169:16: instantiated from
'boost::range_detail::ForwardIteratorConcept<
boost::filter_iterator<main()::<lambda(int)>, int *>
>'
/usr/lib/boost/boost/concept/detail/has_constraints.hpp:42:5: [
skipping 5 instantiation contexts ]
/usr/lib/boost/boost/concept/detail/has_constraints.hpp:42:5:
instantiated from 'const bool boost::concepts::not_satisfied<
boost::ForwardRangeConcept<
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
>
>
>::value'
/usr/lib/boost/boost/concept/detail/has_constraints.hpp:45:31:
instantiated from 'boost::concepts::not_satisfied<
boost::ForwardRangeConcept<
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
>
>
>'
/usr/lib/boost/boost/mpl/if.hpp:67:11: instantiated from 'boost::mpl
::if_<
boost::concepts::not_satisfied<
boost::ForwardRangeConcept<
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
>
>
>, boost::concepts::constraint<
boost::ForwardRangeConcept<
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
>
>
>, boost::concepts::requirement<
boost::concepts::failed ************ boost::ForwardRangeConcept<
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
>
>::************
>
>'
/usr/lib/boost/boost/concept/detail/general.hpp:50:8: instantiated
from 'boost::concepts::requirement_<
void (*)(
boost::ForwardRangeConcept<
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
>
>
)
>'
/usr/lib/boost/boost/range/algorithm/min_element.hpp:43:1:
instantiated from 'boost::range_iterator<const T>::ame boost
::range_iterator<const T>::type = boost::filter_iterator<
main()::<lambda(int)>, int *
> boost::range::min_element(
const boost::range_detail::filtered_range<
main()::<lambda(int)>, int [3]
> &
)'
test.cpp:8:61: instantiated from here
/usr/lib/boost/boost/iterator/filter_iterator.hpp:54:25: error: use of
deleted function 'main()::<lambda(int)>::<lambda>()'
test.cpp:7:20: error: a lambda closure type has a deleted default constructor
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Michel MORIN

unread,
May 30, 2011, 4:50:33 AM5/30/11
to boost...@lists.boost.org
Hi Nate,

Nathan Ridge wrote:
> I get errors related to lambdas not being default-constructible or copy-assignable
> when using a lambda as a predicate with certain adaptors (e.g. filtered) and
> certain algorithms (e.g. min_element).
>
> The following code illustrates the problem:
>
> #include <boost/range/algorithm/min_element.hpp>
> #include <boost/range/adaptor/filtered.hpp>
> int main()
> {
>    int a[] = {1, 2, 3};
>    auto is_odd = [](int i){ return i % 2 == 1; };
>    boost::min_element(a | boost::adaptors::filtered(is_odd));
> }
>
> The errors are shown below.
>
> Is there a workaround for this?

I don't have any workarounds :-(
but I'd like to make a comment.

I think filter_iterator and transform_iterator should use boost::optional to
cope with this kind of problems. For transform_iterator, there's a trac ticket
https://svn.boost.org/trac/boost/ticket/4189
Unfortunately there is no reaction on this ticket.


Regards,
Michel

Michel MORIN

unread,
May 30, 2011, 5:24:37 AM5/30/11
to boost...@lists.boost.org
Nathan Ridge wrote:
> The following code illustrates the problem:
>
> #include <boost/range/algorithm/min_element.hpp>
> #include <boost/range/adaptor/filtered.hpp>
> int main()
> {
> int a[] = {1, 2, 3};
> auto is_odd = [](int i){ return i % 2 == 1; };
> boost::min_element(a | boost::adaptors::filtered(is_odd));
> }
>
> The errors are shown below.
>
> Is there a workaround for this?

Use oven::regular

boost::min_element(a |
boost::adaptors::filtered(pstade::oven::regular(is_odd))
);

and here is the documentation of oven::regular
http://p-stade.sourceforge.net/oven/doc/html/oven/utilities.html#oven.utilities.regular

*** Note ***
`#define BOOST_RESULT_OF_USE_DECLTYPE` is necessary to compile
the above code. Without this, we have compiler errors (the oven library
seems not fully compatible with new compilers yet).

Akira Takahashi

unread,
May 30, 2011, 4:59:08 AM5/30/11
to boost...@lists.boost.org
Hi, Nathan.

This problem is known issue.
PStade.Oven Library have solution by regular function.
http://p-stade.sourceforge.net/oven/doc/html/oven/utilities.html#oven.utilities.regular

I’ve been doing for now, Oven to Boost.Range porting project.
https://github.com/faithandbrave/OvenToBoost

Using this library you can write as follow:

#include <boost/range/algorithm/min_element.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/regular.hpp>


int main()
{
int a[] = {1, 2, 3};
auto is_odd = [](int i){ return i % 2 == 1; };

boost::min_element(a | boost::adaptors::filtered(boost::regular(is_odd)));
}

or, use regular operator(operator|+) version:

#include <boost/range/algorithm/min_element.hpp>
#include <boost/range/adaptor/regular_extension/filtered.hpp>


int main()
{
int a[] = {1, 2, 3};
auto is_odd = [](int i){ return i % 2 == 1; };

boost::min_element(a |+ boost::adaptors::filtered(is_odd));
}


2011/5/30 Nathan Ridge <zerat...@hotmail.com>:


>
> Hello,
>
> I get errors related to lambdas not being default-constructible or copy-assignable
> when using a lambda as a predicate with certain adaptors (e.g. filtered) and
> certain algorithms (e.g. min_element).
>
> The following code illustrates the problem:
>
> #include <boost/range/algorithm/min_element.hpp>
> #include <boost/range/adaptor/filtered.hpp>
> int main()
> {
>    int a[] = {1, 2, 3};
>    auto is_odd = [](int i){ return i % 2 == 1; };
>    boost::min_element(a | boost::adaptors::filtered(is_odd));
> }
>
> The errors are shown below.
>
> Is there a workaround for this?
>
> Thanks,
> Nate.
>

>>========================
Akira Takahashi
mailto : faitha...@gmail.com
blog : http://d.hatena.ne.jp/faith_and_brave/

Akira Takahashi

unread,
May 30, 2011, 11:34:09 AM5/30/11
to boost...@lists.boost.org
Hi, Michel.

> `#define BOOST_RESULT_OF_USE_DECLTYPE` is necessary to compile
> the above code. Without this, we have compiler errors (the oven library
> seems not fully compatible with new compilers yet).

I am Oven Library mantainer(now manager).
I think implicit BOOST_RESULT_OF_USE_DECLTYPE support shoube Boost side.
C++0x lambda hasn't result_type typedef, but
BOOST_RESULT_OF_USE_DECLTYPE needs user side define. I think
BOOST_RESULT_OF_USE_DECLTYPE is should auto define.

>>========================
Akira Takahashi
mailto:faitha...@gmail.com
blog:http://d.hatena.ne.jp/faith_and_brave/

Michel MORIN

unread,
May 30, 2011, 12:41:24 PM5/30/11
to boost...@lists.boost.org, daniel....@gmail.com
Hi Akira,

Akira Takahashi wrote:
> Hi, Michel.
>
>> `#define BOOST_RESULT_OF_USE_DECLTYPE` is necessary to compile
>> the above code. Without this, we have compiler errors (the oven library
>> seems not fully compatible with new compilers yet).
>
> I am Oven Library mantainer(now manager).

Good to know :)


> C++0x lambda hasn't result_type typedef

Ah, this is the reason for the compiler error. Thanks for correcting me.

(Cc'ing to Daniel)
So, when using boost::result_of with C++0x lambda functions,
we have to define BOOST_RESULT_OF_USE_DECLTYPE.
This is a bit bothersome, and so I expect that, in the future,
BOOST_RESULT_OF_USE_DECLTYPE gets automatically defined
in compilers with N3276 support.
Something like
// boost/utility/result_of.hpp
#ifndef #BOOST_NO_DECLTYPE_N3276
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
?
(BOOST_NO_DECLTYPE_N3276 is not yet included in Boost.Config.)


Regards,
Michel

Nathan Ridge

unread,
May 30, 2011, 6:35:44 PM5/30/11
to Boost Mailing List

Thank you Michel and Akira! The regular() solution works well.

Akira, do you have any plans to submit OvenToBoost for inclusion in Boost.Range?

Thanks,
Nate.

Akira Takahashi

unread,
May 30, 2011, 8:24:28 PM5/30/11
to boost...@lists.boost.org
> Akira, do you have any plans to submit OvenToBoost for inclusion in Boost.Range?

I am going to submit it if I finish writing a document.
Quickbook & English is difficult...


>>========================
Akira Takahashi
mailto:faitha...@gmail.com
blog:http://d.hatena.ne.jp/faith_and_brave/

Daniel Walker

unread,
May 30, 2011, 3:46:41 PM5/30/11
to boost...@lists.boost.org
On Mon, May 30, 2011 at 12:41 PM, Michel MORIN <mimo...@gmail.com> wrote:
> Akira Takahashi wrote:
>> C++0x lambda hasn't result_type typedef
>
> Ah, this is the reason for the compiler error. Thanks for correcting me.
>
> (Cc'ing to Daniel)
> So, when using boost::result_of with C++0x lambda functions,
> we have to define BOOST_RESULT_OF_USE_DECLTYPE.
> This is a bit bothersome, and so I expect that, in the future,
> BOOST_RESULT_OF_USE_DECLTYPE gets automatically defined
> in compilers with N3276 support.
> Something like
> // boost/utility/result_of.hpp
> #ifndef #BOOST_NO_DECLTYPE_N3276
> #define BOOST_RESULT_OF_USE_DECLTYPE
> #endif
> ?
> (BOOST_NO_DECLTYPE_N3276 is not yet included in Boost.Config.)

At some point, BOOST_RESULT_OF_USE_DECLTYPE may be defined by default,
probably when there's enough user interest, so thanks for cc'ing me.
The reason it is currently not defined by default is that it is
possible that it could introduce breaking changes to some C++03
function objects; e.g. if a function object defines result_type to be
some type other than the type of a call expression, then in C++03
result_of would give the user-specified result_type rather than the
actual result type, whereas in C++0x result_of always gives the actual
result type. For example:

#include <boost/type_traits.hpp>
#include <boost/utility/result_of.hpp>

struct f {
typedef int result_type;
double operator()(double);
};

int main()
{
using namespace boost;
typedef result_of<f(double)>::type type;
#ifdef BOOST_RESULT_OF_USE_DECLTYPE
static_assert(is_same<type, double>::value, "");
#else
static_assert(is_same<type, int>::value, "");
#endif
}

Also, I'm sure a config macro will be added for N3276, though I'm not
sure what its exact name will be. For example, current decltype
implementations work in context where the result type is complete.
N3276 requires them to also work in context where the result type is
incomplete. So, a more descriptive name might be
BOOST_NO_INCOMPLETE_DECLTYPE.

Daniel Walker

Michel MORIN

unread,
May 31, 2011, 9:37:17 PM5/31/11
to boost...@lists.boost.org, daniel....@gmail.com
Hi Daniel,

Daniel Walker wrote:
> At some point, BOOST_RESULT_OF_USE_DECLTYPE may be defined by default,
> probably when there's enough user interest, so thanks for cc'ing me.
> The reason it is currently not defined by default is that it is
> possible that it could introduce breaking changes to some C++03
> function objects; e.g. if a function object defines result_type to be
> some type other than the type of a call expression, then in C++03
> result_of would give the user-specified result_type rather than the
> actual result type, whereas in C++0x result_of always gives the actual
> result type. For example:
>
> #include <boost/type_traits.hpp>
> #include <boost/utility/result_of.hpp>
>
> struct f {
>    typedef int result_type;
>    double operator()(double);
> };
>
> int main()
> {
>    using namespace boost;
>    typedef result_of<f(double)>::type type;
> #ifdef BOOST_RESULT_OF_USE_DECLTYPE
>    static_assert(is_same<type, double>::value, "");
> #else
>    static_assert(is_same<type, int>::value, "");
> #endif
> }

Thank you for explaining the problem.
And yes, backward compatibility is always problematic.

IMO, this use case is not the intended use of boost::result_of,
so is it reasonable to deprecate this?
And how about adding a "Note" that warns this kind of codes will break
in the future to the documentation?

Regards,
Michel

P.S. Eric just completed a patch for BOOST_NO_DECLTYPE_N3276:
http://permalink.gmane.org/gmane.comp.lib.boost.devel/219979

Daniel Walker

unread,
Jun 1, 2011, 4:07:58 PM6/1/11
to Michel MORIN, boost...@lists.boost.org

This is not an intended (or supported) use case at all. Nevertheless,
it seemed reasonable to roll out decltype slowly.

> And how about adding a "Note" that warns this kind of codes will break
> in the future to the documentation?

Sure. I added the following:

"In a future release, BOOST_RESULT_OF_USE_DECLTYPE may be enabled by
default on compilers that support decltype, so if you use the above
protocol please take care to ensure that the result_type and result<>
members are accurate. If you wish to continue to use the protocol on
compilers that support decltype, use boost::tr1_result_of, which is
also defined in <boost/utility/result_of.hpp>."

Thanks for the suggestions!

Daniel Walker

Michel MORIN

unread,
Jun 3, 2011, 12:57:41 AM6/3/11
to Daniel Walker, boost...@lists.boost.org
Daniel Walker wrote:
> This is not an intended (or supported) use case at all. Nevertheless,
> it seemed reasonable to roll out decltype slowly.

OK, sounds good.


>> And how about adding a "Note" that warns this kind of codes will break
>> in the future to the documentation?
>
> Sure. I added the following:
>
> "In a future release, BOOST_RESULT_OF_USE_DECLTYPE may be enabled by
> default on compilers that support decltype, so if you use the above
> protocol please take care to ensure that the result_type and result<>
> members are accurate. If you wish to continue to use the protocol on
> compilers that support decltype, use boost::tr1_result_of, which is
> also defined in <boost/utility/result_of.hpp>."

That's great, Daniel! Thank you for your quick work.
Just a minor suggenstion:

"the result_type and result<> members are accurate."

-->
"the result_type and result<> members accurately represent the result type."

IMHO, the latter is more clear.


Regards,
Michel

Reply all
Reply to author
Forward
0 new messages