boost::ptr_vector::sort with c++11 lambdas

I am trying to figure out if c++11 lambda can be used instead of the straight preducates. say, I have class A : public boost::noncopyable { ... } and boost::ptr_vector<A> lst; I'd like to use something like: lst.sort([&] (const A& v1, const A& v2) ->bool {return v1 < v2;}); Tutorial for ptr_vector says that predicates are wrapped in indirect_fun. May be this is the reason the sort fails to compile?

Den 11-11-2011 13:52, qplace skrev:
I am trying to figure out if c++11 lambda can be used instead of the straight preducates.
say, I have class A : public boost::noncopyable { ... }
and
boost::ptr_vector<A> lst;
I'd like to use something like:
lst.sort([&] (const A& v1, const A& v2) ->bool {return v1< v2;});
Tutorial for ptr_vector says that predicates are wrapped in indirect_fun. May be this is the reason the sort fails to compile?
Could be. What does the error message say? I'm thinking that the lambda function is not properly converted to a pointer to a function. An escape route may be to use std::sort() with a lambda taking two void*. -Thorsten

Thorsten Ottosen <thorsten.ottosen <at> dezide.com> writes:
Could be. What does the error message say?
I'm thinking that the lambda function is not properly converted to a pointer to a function.
An escape route may be to use std::sort() with a lambda taking two void*.
-Thorsten
The first error is: 1>c:\libraries\boost\boost_1_47_0\boost\utility\result_of.hpp(79): error C2903: 'result' : symbol is neither a class template nor a function template changing to void* results in the same error. Test project is this one: #include <boost/noncopyable.hpp> #include <boost/ptr_container/ptr_vector.hpp> class A : public boost::noncopyable { public: A() {} }; int _tmain(int argc, _TCHAR* argv[]) { boost::ptr_vector<A> lst; // lst.sort([&] (const A& v1, const A& v2) ->bool {return false;}); lst.sort([] (const A* v1, const A* v2) ->bool {return false;}); return 0; }

Den 11-11-2011 15:30, qplace skrev:
Thorsten Ottosen<thorsten.ottosen<at> dezide.com> writes:
Could be. What does the error message say?
I'm thinking that the lambda function is not properly converted to a pointer to a function.
An escape route may be to use std::sort() with a lambda taking two void*.
-Thorsten
The first error is: 1>c:\libraries\boost\boost_1_47_0\boost\utility\result_of.hpp(79): error C2903: 'result' : symbol is neither a class template nor a function template
changing to void* results in the same error.
I'm saying use std::sort() with void* arguments.
// lst.sort([&] (const A& v1, const A& v2) ->bool {return false;}); lst.sort([] (const A* v1, const A* v2) ->bool {return false;});
The first one is the correct one. But I think the problem is with indirect_fun, or the code surrounding it. Does this work: auto x = <lambda>; boost::indirect_fun<decltype(x)> fun(x); ? -Thorsten

Thorsten Ottosen <thorsten.ottosen <at> dezide.com> writes:
The first one is the correct one. But I think the problem is with indirect_fun, or the code surrounding it. Does this work:
auto x = <lambda>;
boost::indirect_fun<decltype(x)> fun(x);
?
-Thorsten
int _tmain(int argc, _TCHAR* argv[]) { boost::ptr_vector<A> lst; // lst.sort([&] (const A& v1, const A& v2) ->bool {return false;}); auto x = [] (const A* v1, const A* v2) ->bool {return false;}; boost::indirect_fun<decltype(x)> fun(x); lst.sort(fun); return 0; } The error message is the same. Complete output is shown below: 1>ClCompile: 1>c:\libraries\boost\boost_1_47_0\boost\utility\result_of.hpp(79): error C2903: 'result' : symbol is neither a class template nor a function template 1> c:\libraries\boost\boost_1_47_0\boost\utility\result_of.hpp(87) : see reference to class template instantiation 'boost::detail::result_of_nested_result<F,FArgs>' being compiled 1> with 1> [ 1> F=const boost::indirect_fun<`anonymous-namespace'::<lambda0>>, 1> FArgs=const boost::indirect_fun<`anonymous- namespace'::<lambda0>> (const A &,const A &) 1> ] 1> c:\libraries\boost\boost_1_47_0 \boost\utility\detail\result_of_iterate.hpp(33) : see reference to class template instantiation 'boost::detail::tr1_result_of_impl<F,FArgs,HasResultType>' being compiled 1> with 1> [ 1> F=const boost::indirect_fun<`anonymous-namespace'::<lambda0>>, 1> FArgs=const boost::indirect_fun<`anonymous- namespace'::<lambda0>> (const A &,const A &), 1> HasResultType=false 1> ] 1> c:\libraries\boost\boost_1_47_0 \boost\utility\detail\result_of_iterate.hpp(81) : see reference to class template instantiation 'boost::tr1_result_of<F>' being compiled 1> with 1> [ 1> F=const boost::indirect_fun<`anonymous-namespace'::<lambda0>> (const A &,const A &) 1> ] 1> c:\libraries\boost\boost_1_47_0\boost\ptr_container\indirect_fun.hpp (41) : see reference to class template instantiation 'boost::result_of<F>' being compiled 1> with 1> [ 1> F=const boost::indirect_fun<`anonymous-namespace'::<lambda0>> (const A &,const A &) 1> ] 1> c:\program files (x86)\microsoft visual studio 10.0 \vc\include\algorithm(3720) : see reference to class template instantiation 'boost::ptr_container_detail::make_lazy<Type,Dummy>' being compiled 1> with 1> [ 1> Type=boost::result_of<const boost::indirect_fun<`anonymous- namespace'::<lambda0>> (const A &,const A &)>, 1> Dummy=void 1> ] 1> c:\program files (x86)\microsoft visual studio 10.0 \vc\include\algorithm(3776) : see reference to function template instantiation 'std::pair<_Ty1,_Ty2> std::_Unguarded_partition<_RanIt,_Pr> (_RanIt,_RanIt,_Pr)' being compiled 1> with 1> [ 1> _Ty1=void **, 1> _Ty2=void **, 1> _RanIt=void **, 1> _Pr=boost::void_ptr_indirect_fun<boost::indirect_fun<`anonymous- namespace'::<lambda0>>,A> 1> ] 1> c:\program files (x86)\microsoft visual studio 10.0 \vc\include\algorithm(3806) : see reference to function template instantiation 'void std::_Sort<void**,__w64 int,_Pr>(_RanIt,_RanIt,_Diff,_Pr)' being compiled 1> with 1> [ 1> _Pr=boost::void_ptr_indirect_fun<boost::indirect_fun<`anonymous- namespace'::<lambda0>>,A>, 1> _RanIt=void **, 1> _Diff=__w64 int 1> ] 1> c:\libraries\boost\boost_1_47_0 \boost\ptr_container\ptr_sequence_adapter.hpp(601) : see reference to function template instantiation 'void std::sort<VoidIter,boost::void_ptr_indirect_fun<Fun,Arg1>>(_RanIt,_RanIt,_Pr)' being compiled 1> with 1> [ 1> VoidIter=std::_Vector_iterator<std::_Vector_val<void *,std::allocator<void *>>>, 1> Fun=boost::indirect_fun<`anonymous-namespace'::<lambda0>>, 1> Arg1=A, 1> _RanIt=std::_Vector_iterator<std::_Vector_val<void *,std::allocator<void *>>>, 1> _Pr=boost::void_ptr_indirect_fun<boost::indirect_fun<`anonymous- namespace'::<lambda0>>,A> 1> ] 1> c:\libraries\boost\boost_1_47_0 \boost\ptr_container\ptr_sequence_adapter.hpp(607) : see reference to function template instantiation 'void boost::ptr_sequence_adapter<T,VoidPtrSeq,CloneAllocator>::sort<Compare> (boost::void_ptr_iterator<VoidIter,T>,boost::void_ptr_iterator<VoidIter,T>,Compa re)' being compiled 1> with 1> [ 1> T=A, 1> VoidPtrSeq=std::vector<void *,std::allocator<void *>>, 1> CloneAllocator=boost::heap_clone_allocator, 1> Compare=boost::indirect_fun<`anonymous-namespace'::<lambda0>>, 1> VoidIter=std::_Vector_iterator<std::_Vector_val<void *,std::allocator<void *>>> 1> ] 1> c:\test\ptr_pointer_lambda\ptr_pointer_lambda\ptr_pointer_lambda.cpp (23) : see reference to function template instantiation 'void boost::ptr_sequence_adapter<T,VoidPtrSeq,CloneAllocator>::sort<boost::indirect_f un<Fun>>(Compare)' being compiled 1> with 1> [ 1> T=A, 1> VoidPtrSeq=std::vector<void *,std::allocator<void *>>, 1> CloneAllocator=boost::heap_clone_allocator, 1> Fun=`anonymous-namespace'::<lambda0>, 1> Compare=boost::indirect_fun<`anonymous-namespace'::<lambda0>> 1> ] 1>c:\libraries\boost\boost_1_47_0\boost\utility\result_of.hpp(79): error C2039: 'result' : is not a member of 'boost::indirect_fun<Fun>' 1> with 1> [ 1> Fun=`anonymous-namespace'::<lambda0> 1> ] 1>c:\libraries\boost\boost_1_47_0\boost\utility\result_of.hpp(79): error C2504: 'result' : base class undefined 1>c:\libraries\boost\boost_1_47_0\boost\utility\result_of.hpp(79): error C2143: syntax error : missing ',' before '<' 1>c:\libraries\boost\boost_1_47_0\boost\ptr_container\indirect_fun.hpp(41): error C2039: 'type' : is not a member of 'boost::result_of<F>' 1> with 1> [ 1> F=const boost::indirect_fun<`anonymous-namespace'::<lambda0>> (const A &,const A &) 1> ] 1>c:\libraries\boost\boost_1_47_0\boost\ptr_container\indirect_fun.hpp(41): error C2146: syntax error : missing ';' before identifier 'type' 1>c:\libraries\boost\boost_1_47_0\boost\ptr_container\indirect_fun.hpp(41): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int 1>c:\libraries\boost\boost_1_47_0\boost\ptr_container\indirect_fun.hpp(41): error C2602: 'boost::ptr_container_detail::make_lazy<Type,Dummy>::type' is not a member of a base class of 'boost::ptr_container_detail::make_lazy<Type,Dummy>' 1> with 1> [ 1> Type=boost::result_of<const boost::indirect_fun<`anonymous- namespace'::<lambda0>> (const A &,const A &)>, 1> Dummy=void 1> ] 1> c:\libraries\boost\boost_1_47_0\boost\ptr_container\indirect_fun.hpp (41) : see declaration of 'boost::ptr_container_detail::make_lazy<Type,Dummy>::type' 1> with 1> [ 1> Type=boost::result_of<const boost::indirect_fun<`anonymous- namespace'::<lambda0>> (const A &,const A &)>, 1> Dummy=void 1> ] 1>c:\libraries\boost\boost_1_47_0\boost\ptr_container\indirect_fun.hpp(41): error C2868: 'boost::ptr_container_detail::make_lazy<Type,Dummy>::type' : illegal syntax for using-declaration; expected qualified-name 1> with 1> [ 1> Type=boost::result_of<const boost::indirect_fun<`anonymous- namespace'::<lambda0>> (const A &,const A &)>, 1> Dummy=void 1> ]

The following code compiles fine. Is this what you want? #define BOOST_RESULT_OF_USE_DECLTYPE #include <boost/noncopyable.hpp> #include <boost/ptr_container/ptr_vector.hpp> class A : public boost::noncopyable { public: A() {} }; int main (int argc, char* argv[]) { boost::ptr_vector<A> lst; lst.sort([&] (const A& v1, const A& v2) ->bool {return false;}); return 0; } Regards, Michel

Hello, Just one remark - you should inherit from boost::noncopyable privately. boost::noncopyable has no virtual dtor and no one should be able to obtain that base from any derived classes. At the same time noncopyable property will retain for the whole inheritance chain. Regards, Dmitriy. -- С уважением, Матисон Дмитрий.

Michel Morin <mimomorin <at> gmail.com> writes:
The following code compiles fine. Is this what you want?
#define BOOST_RESULT_OF_USE_DECLTYPE
Exactly, thank you for the solution, it compiles fine now. A follow-up question: what this #define does? Google'ing it it does not provide a reference to the doc, only to unrelated discussions. May be you have a direct link to the documentation page? Thanks.

qplace wrote:
Exactly, thank you for the solution, it compiles fine now. A follow-up question: what this #define does? Google'ing it it does not provide a reference to the doc, only to unrelated discussions. May be you have a direct link to the documentation page?
`indirect_fun` uses `result_of` to determine the return type of a functor. So the functor should have `result_type` nested-type or struct `result`. If the functor do not have them, we can use C++11 `decltype` feature to determine its return type (C++11 lambdas do not have them). To enable this feature, we have to define `BOOST_RESULT_OF_USE_DECLTYPE`. For BOOST_RESULT_OF_USE_DECLTYPE, please see http://www.boost.org/doc/libs/1_47_0/libs/utility/utility.htm#result_of Regards, Michel

Le 11/11/11 18:58, Michel Morin a écrit :
qplace wrote:
Exactly, thank you for the solution, it compiles fine now. A follow-up question: what this #define does? Google'ing it it does not provide a reference to the doc, only to unrelated discussions. May be you have a direct link to the documentation page? `indirect_fun` uses `result_of` to determine the return type of a functor. So the functor should have `result_type` nested-type or struct `result`. If the functor do not have them, we can use C++11 `decltype` feature to determine its return type (C++11 lambdas do not have them). To enable this feature, we have to define `BOOST_RESULT_OF_USE_DECLTYPE`.
For BOOST_RESULT_OF_USE_DECLTYPE, please see http://www.boost.org/doc/libs/1_47_0/libs/utility/utility.htm#result_of
Hi, is there any reason result_of couldn't use decltype when available? That is, could Boost define BOOST_RESULT_OF_USE_DECLTYPE when decltype is supporeted? Best, Vicente

Vicente J. Botet Escriba wrote:
is there any reason result_of couldn't use decltype when available? That is, could Boost define BOOST_RESULT_OF_USE_DECLTYPE when decltype is supporeted?
First, (almost) all current implementation of decltype does not support N3276. Non-N3276-decltype requires type-completeness, while traditional result_of does not. So result_of with non-N3276-decltype is incompatible with the traditional result_of. We should proceed gradually even if N3276-decltype is available, because * decltype-based result_of can break user codes with (unintended) use of result_of. * Implementation of N3276-decltype might be buggy for some time. Daniel already made a first step by updating the documentation. The doc on trunk says: 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 accurately represent the result type. 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>. Regards, Michel

Le 12/11/11 05:34, Michel Morin a écrit :
Vicente J. Botet Escriba wrote:
is there any reason result_of couldn't use decltype when available? That is, could Boost define BOOST_RESULT_OF_USE_DECLTYPE when decltype is supporeted? First, (almost) all current implementation of decltype does not support N3276. Non-N3276-decltype requires type-completeness, while traditional result_of does not. So result_of with non-N3276-decltype is incompatible with the traditional result_of.
We should proceed gradually even if N3276-decltype is available, because * decltype-based result_of can break user codes with (unintended) use of result_of. * Implementation of N3276-decltype might be buggy for some time.
Daniel already made a first step by updating the documentation. The doc on trunk says: 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 accurately represent the result type. 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 clarification. So if IUC, the use of BOOST_RESULT_OF_USE_DECLTYPE in the user code could break other parts of her application, isn't it? Best, Vicente

Vicente J. Botet Escriba wrote:
We should proceed gradually even if N3276-decltype is available, because * decltype-based result_of can break user codes with (unintended) use of result_of. * Implementation of N3276-decltype might be buggy for some time.
Thanks for the clarification. So if IUC, the use of BOOST_RESULT_OF_USE_DECLTYPE in the user code could break other parts of her application, isn't it?
Right. There are two types of breakage. (But note that the correct support of the traditional result_of protocol and the correct usage of result_of should not make any breakage with BOOST_RESULT_OF_USE_DECLTYPE + N3276-decltype. So, I think, you don't have to worry about the breakage too much.) 1) Breakage caused by type-completeness requirement of non-N3276-decltype Boost.Proto uses boost::tr1_result_of to avoid this problem. boost::tr1_result_of uses the traditional implementation of result_of even if BOOST_RESULT_OF_USE_DECLTYPE is defined. 2) Breakage caused by incorrect support or incorrect usage of result_of Some codes using Boost.Fusion or Boost.Phoenix fail to compile if BOOST_RESULT_OF_USE_DECLTYPE is defined. http://thread.gmane.org/gmane.comp.parsers.spirit.general/24027 https://svn.boost.org/trac/boost/ticket/5687 Regards, Michel
participants (5)
-
Dmitriy Matison
-
Michel Morin
-
qplace
-
Thorsten Ottosen
-
Vicente J. Botet Escriba