[MPL] Bug with default lambda expressions?
Hi, Some higher order algorithms in the MPL have a default for the lambda expression they accept. A good example is `boost::mpl::equal`: template <typename S1, typename S2, typename Pred = is_same<_, _> > struct equal; This works fine most of the time, but I was recently bitten by the following: template <typename VectorOfVectors, typename Vector> struct find_vector : find_if< VectorOfVectors, equal<Vector, _1> > { }; typedef find_vector< vector< vector<int, int>, vector<char, char> >, vector<char, char> >::type ThisWillBreak; What happens here is that the `equal<Vector, _1>` expression inside `find_vector` really is `equal<Vector, _1, is_same<_1, _2> >` because of the default value for the predicate to `equal`. When the lambda is evaluated, the placholders inside the inner `is_same<_1, _2>` expression are replaced too, which yields unexpected results. Using template <typename S1, typename S2, typename Pred = typename lambda<is_same<_, _> >::type> struct equal; or equivalently template <typename S1, typename S2, typename Pred = quote2<is_same> > struct equal; fixes the issue. Also note that all of the unit tests of the MPL still pass with these changes. Is the current behavior intended, or should I submit a patch? Regards, Louis Dionne
On 13-05-21 01:43 PM, Louis Dionne wrote:
Hi,
Some higher order algorithms in the MPL have a default for the lambda expression they accept. A good example is `boost::mpl::equal`:
template <typename S1, typename S2, typename Pred = is_same<_, _> > struct equal;
This works fine most of the time, but I was recently bitten by the following:
template <typename VectorOfVectors, typename Vector> struct find_vector : find_if< VectorOfVectors, equal<Vector, _1> > { };
typedef find_vector< vector< vector<int, int>, vector<char, char> >, vector<char, char> >::type ThisWillBreak;
What happens here is that the `equal<Vector, _1>` expression inside `find_vector` really is `equal<Vector, _1, is_same<_1, _2> >` because of the default value for the predicate to `equal`. When the lambda is evaluated, the placholders inside the inner `is_same<_1, _2>` expression are replaced too, which yields unexpected results.
Using
template <typename S1, typename S2, typename Pred = typename lambda<is_same<_, _> >::type> struct equal;
or equivalently
template <typename S1, typename S2, typename Pred = quote2<is_same> > struct equal;
fixes the issue. Also note that all of the unit tests of the MPL still pass with these changes. Is the current behavior intended, or should I submit a patch?
I'm not an expert, but it sounds like a bug to me. You should probably file it (http://svn.boost.org) so it doesn't get lost. Assign it to Aleksey Gurtovoy (agurtovoy). A patch certainly couldn't hurt. Even better if it came with a test. :-) -- Eric Niebler Boost.org
On 05/21/13 15:43, Louis Dionne wrote:
Hi,
Some higher order algorithms in the MPL have a default for the lambda expression they accept. A good example is `boost::mpl::equal`:
template <typename S1, typename S2, typename Pred = is_same<_, _> > struct equal;
This works fine most of the time, but I was recently bitten by the following:
template <typename VectorOfVectors, typename Vector> struct find_vector : find_if< VectorOfVectors, equal<Vector, _1> > { };
typedef find_vector< vector< vector<int, int>, vector<char, char> >, vector<char, char> >::type ThisWillBreak;
What happens here is that the `equal<Vector, _1>` expression inside `find_vector` really is `equal<Vector, _1, is_same<_1, _2> >` because of the default value for the predicate to `equal`. When the lambda is evaluated, the placholders inside the inner `is_same<_1, _2>` expression are replaced too, which yields unexpected results.
Using
template <typename S1, typename S2, typename Pred = typename lambda<is_same<_, _> >::type> struct equal;
or equivalently
template <typename S1, typename S2, typename Pred = quote2<is_same> > struct equal;
fixes the issue. Also note that all of the unit tests of the MPL still pass with these changes. Is the current behavior intended, or should I submit a patch?
Regards,
Louis Dionne
This sounds like a problem similar to the one here: http://article.gmane.org/gmane.comp.lib.boost.devel/227344 Maybe reading that thread would give you some ideas for a solution. HTH. Larry
On 05/21/13 18:04, Larry Evans wrote:
On 05/21/13 15:43, Louis Dionne wrote:
Hi,
Some higher order algorithms in the MPL have a default for the lambda expression they accept. A good example is `boost::mpl::equal`:
template <typename S1, typename S2, typename Pred = is_same<_, _> > struct equal;
This works fine most of the time, but I was recently bitten by the following:
template <typename VectorOfVectors, typename Vector> struct find_vector : find_if< VectorOfVectors, equal<Vector, _1> > { };
typedef find_vector< vector< vector<int, int>, vector<char, char> >, vector<char, char> >::type ThisWillBreak;
What happens here is that the `equal<Vector, _1>` expression inside `find_vector` really is `equal<Vector, _1, is_same<_1, _2> >` because of the default value for the predicate to `equal`. When the lambda is evaluated, the placholders inside the inner `is_same<_1, _2>` expression are replaced too, which yields unexpected results.
Using
template <typename S1, typename S2, typename Pred = typename lambda<is_same<_, _> >::type> struct equal;
or equivalently
template <typename S1, typename S2, typename Pred = quote2<is_same> > struct equal;
fixes the issue. Also note that all of the unit tests of the MPL still pass with these changes. Is the current behavior intended, or should I submit a patch?
Regards,
Louis Dionne
This sounds like a problem similar to the one here:
http://article.gmane.org/gmane.comp.lib.boost.devel/227344
Maybe reading that thread would give you some ideas for a solution.
OOPS. I should have read further and noted your solution using lambda. Sorry for noise. However, with the attached and your changes and gcc4.8 I'm getting errors: bug_with_default_lambda.cpp:18:12: required from 'struct find_vector<boost::mpl::vector<boost::mpl::vector<int, int>, boost::mpl::vector<char, char> >, boost::mpl::vector<char, char> >' bug_with_default_lambda.cpp:30:6: required from here /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp:36:8: error: no class template named 'apply' in 'struct boost::mpl::equal<boost::mpl::vector<char, char>, mpl_::arg<1>, boost::mpl::protect<boost::mpl::bind2<boost::mpl::quote2<boost::is_same, mpl_::void_>, mpl_::arg<-1>, mpl_::arg<-1> >, 0> >' struct apply_wrap1 ^ In file included from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/not.hpp:19:0, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/assert.hpp:17, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/aux_/na_assert.hpp:23, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/arg.hpp:25, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/placeholders.hpp:24, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/apply.hpp:24, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/aux_/iter_fold_if_impl.hpp:22, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/equal.hpp:17, from bug_with_default_lambda.cpp:10: . . . The mpl/equal.hpp contains your suggested modification: template< typename BOOST_MPL_AUX_NA_PARAM(Sequence1) , typename BOOST_MPL_AUX_NA_PARAM(Sequence2) #ifdef LJE_USE_LAMBDA_PREDICATE_IS_SAME , typename Predicate = typename lambda<is_same<_,_> >::type #else , typename Predicate = is_same<_,_> #endif > struct equal : aux::msvc_eti_base< typename aux::equal_impl<Sequence1,Sequence2,Predicate>::type >::type { BOOST_MPL_AUX_LAMBDA_SUPPORT(2,equal,(Sequence1,Sequence2)) }; Could you supply a complete test case so I can see what I might be doing wrong to reproduce your solution? TIA. -regards, Larry
On 05/22/13 07:16, Larry Evans wrote:
On 05/21/13 18:04, Larry Evans wrote:
On 05/21/13 15:43, Louis Dionne wrote:
Hi,
Some higher order algorithms in the MPL have a default for the lambda expression they accept. A good example is `boost::mpl::equal`:
template <typename S1, typename S2, typename Pred = is_same<_, _> > struct equal;
This works fine most of the time, but I was recently bitten by the following:
template <typename VectorOfVectors, typename Vector> struct find_vector : find_if< VectorOfVectors, equal<Vector, _1> > { };
typedef find_vector< vector< vector<int, int>, vector<char, char> >, vector<char, char> >::type ThisWillBreak;
What happens here is that the `equal<Vector, _1>` expression inside `find_vector` really is `equal<Vector, _1, is_same<_1, _2> >` because of the default value for the predicate to `equal`. When the lambda is evaluated, the placholders inside the inner `is_same<_1, _2>` expression are replaced too, which yields unexpected results.
Using
template <typename S1, typename S2, typename Pred = typename lambda<is_same<_, _> >::type> struct equal;
or equivalently
template <typename S1, typename S2, typename Pred = quote2<is_same> > struct equal;
fixes the issue. Also note that all of the unit tests of the MPL still pass with these changes. Is the current behavior intended, or should I submit a patch?
Regards,
Louis Dionne
This sounds like a problem similar to the one here:
http://article.gmane.org/gmane.comp.lib.boost.devel/227344
Maybe reading that thread would give you some ideas for a solution.
OOPS. I should have read further and noted your solution using lambda. Sorry for noise.
However, with the attached and your changes and gcc4.8 I'm getting errors:
bug_with_default_lambda.cpp:18:12: required from 'struct find_vector<boost::mpl::vector<boost::mpl::vector<int, int>, boost::mpl::vector<char, char> >, boost::mpl::vector<char, char> >' bug_with_default_lambda.cpp:30:6: required from here /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp:36:8: error: no class template named 'apply' in 'struct boost::mpl::equal<boost::mpl::vector<char, char>, mpl_::arg<1>, boost::mpl::protect<boost::mpl::bind2<boost::mpl::quote2<boost::is_same, mpl_::void_>, mpl_::arg<-1>, mpl_::arg<-1> >, 0> >' struct apply_wrap1 ^ In file included from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/not.hpp:19:0, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/assert.hpp:17, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/aux_/na_assert.hpp:23, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/arg.hpp:25, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/placeholders.hpp:24, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/apply.hpp:24, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/aux_/iter_fold_if_impl.hpp:22, from /home/evansl/prog_dev/boost-svn/ro/boost_1_53_0/boost/mpl/equal.hpp:17, from bug_with_default_lambda.cpp:10: . . .
The mpl/equal.hpp contains your suggested modification:
template< typename BOOST_MPL_AUX_NA_PARAM(Sequence1) , typename BOOST_MPL_AUX_NA_PARAM(Sequence2) #ifdef LJE_USE_LAMBDA_PREDICATE_IS_SAME , typename Predicate = typename lambda<is_same<_,_> >::type #else , typename Predicate = is_same<_,_> #endif > struct equal : aux::msvc_eti_base< typename aux::equal_impl<Sequence1,Sequence2,Predicate>::type >::type { BOOST_MPL_AUX_LAMBDA_SUPPORT(2,equal,(Sequence1,Sequence2)) };
Could you supply a complete test case so I can see what I might be doing wrong to reproduce your solution?
TIA.
-regards, Larry
Strangely enough, when the changes to mpl/equal.hpp were backed out, and the lambda was put in test driver, as shown in attached, it compiles OK. -Larry
[...]
Could you supply a complete test case so I can see what I might be doing wrong to reproduce your solution? [...]
Sorry for taking so long to reply. I created a ticket and uploaded a test case, code fix and documentation fix for the issue: https://svn.boost.org/trac/boost/ticket/8608 However, I do not fully understand the implications of my code fix (changing the arity supplied to BOOST_MPL_AUX_NA_SPEC and BOOST_MPL_AUX_LAMBDA_SUPPORT), so it would be best for someone familiar with these to review my changes before anything is applied. Also, if I uncovered a real problem and if we have a good fix for it, we should make sure that no other higher order algorithm suffer from the same issue. Louis
On Wed, May 22, 2013 at 2:33 PM, Louis Dionne <ldionne.2@gmail.com> wrote:
[...]
Could you supply a complete test case so I can see what I might be doing wrong to reproduce your solution? [...]
Sorry for taking so long to reply. I created a ticket and uploaded a test case, code fix and documentation fix for the issue: https://svn.boost.org/trac/boost/ticket/8608
However, I do not fully understand the implications of my code fix (changing the arity supplied to BOOST_MPL_AUX_NA_SPEC and BOOST_MPL_AUX_LAMBDA_SUPPORT), so it would be best for someone familiar with these to review my changes before anything is applied.
Also, if I uncovered a real problem and if we have a good fix for it, we should make sure that no other higher order algorithm suffer from the same issue.
+1 - Jeff
On Wed, May 22, 2013 at 5:16 AM, Larry Evans <cppljevans@suddenlink.net>wrote:
On 05/21/13 18:04, Larry Evans wrote:
On 05/21/13 15:43, Louis Dionne wrote:
[...]
template <typename S1, typename S2, typename Pred = is_same<_, _> > struct equal;
[...]
template< typename BOOST_MPL_AUX_NA_PARAM(Sequence1) , typename BOOST_MPL_AUX_NA_PARAM(Sequence2) #ifdef LJE_USE_LAMBDA_PREDICATE_IS_SAME , typename Predicate = typename lambda<is_same<_,_> >::type #else , typename Predicate = is_same<_,_> #endif > struct equal
[...] Quick note: might as well use quote2<is_same> rather than lambda<is_same<_,_>>::type...at least, I think so, I've never actually used mpl::_ myself. - Jeff
participants (5)
-
Eric Niebler
-
Jeffrey Lee Hellrung, Jr.
-
Larry Evans
-
Louis Dionne
-
Louis Dionne