[ptr_container] compiler error with BOOST_RESULT_OF_USE_DECLTYPE
Hello, The following code: #include <boost/ptr_container/ptr_set.hpp> struct A { bool operator<(const A&) const; }; int main() { boost::ptr_set<A> s; return 0; } gives the following compiler errors when compiling with BOOST_RESULT_OF_USE_DECLTYPE defined: In file included from ../../lib/boost- 1.45/boost/preprocessor/iteration/detail/iter/forward1.hpp:52:0, from ../../lib/boost-1.45/boost/utility/result_of.hpp:92, from ../../lib/boost-1.45/boost/ptr_container/indirect_fun.hpp:23, from ../../lib/boost-1.45/boost/ptr_container/ptr_set.hpp:19, from test.cpp:1: ../../lib/boost-1.45/boost/utility/detail/result_of_iterate.hpp: In instantiation of 'boost::detail::cpp0x_result_of_impl<less<A>(A &)>': ../../lib/boost-1.45/boost/utility/detail/result_of_iterate.hpp:44:8: instantiated from 'boost::result_of<less<A>(A &)>' ../../lib/boost-1.45/boost/ptr_container/indirect_fun.hpp:107:9: instantiated from 'boost::void_ptr_indirect_fun<less<A>, A, A>' stl_tree.h:462:31: instantiated from '_Rb_tree< void *, void *, _Identity<void *> , boost::void_ptr_indirect_fun<less<A>, A, A> >' stl_set.h:112:17: instantiated from 'set< void *, boost::void_ptr_indirect_fun<less<A>, A, A> >' ../../lib/boost-1.45/boost/ptr_container/ptr_set_adapter.hpp:40:21: instantiated from 'boost::ptr_container_detail::set_config< A, set<void *, boost::void_ptr_indirect_fun<less<A>, A, A> >, true >' ../../lib/boost-1.45/boost/ptr_container/detail/reversible_ptr_container.hpp:87:59: instantiated from 'boost::ptr_container_detail::reversible_ptr_container< boost::ptr_container_detail::set_config< A, set<void *, boost::void_ptr_indirect_fun<less<A>, A, A> >, true >, boost::heap_clone_allocator >' ../../lib/boost-1.45/boost/ptr_container/detail/associative_ptr_container.hpp:32:11: instantiated from 'boost::ptr_container_detail::associative_ptr_container< boost::ptr_container_detail::set_config< A, set<void *, boost::void_ptr_indirect_fun<less<A>, A, A> >, true >, boost::heap_clone_allocator >' ../../lib/boost-1.45/boost/ptr_container/ptr_set_adapter.hpp:122:11: instantiated from 'boost::ptr_container_detail::ptr_set_adapter_base< A, set<void *, boost::void_ptr_indirect_fun<less<A>, A, A> > , boost::heap_clone_allocator, true >' ../../lib/boost-1.45/boost/ptr_container/ptr_set_adapter.hpp:299:11: instantiated from 'boost::ptr_set_adapter< A, set<void *, boost::void_ptr_indirect_fun<less<A>, A, A> > , boost::heap_clone_allocator, true >' ../../lib/boost-1.45/boost/ptr_container/ptr_set.hpp:33:11: instantiated from 'boost::ptr_set<A>' ../shared/test/test.cpp:10:23: instantiated from here ../../lib/boost-1.45/boost/utility/detail/result_of_iterate.hpp:70:69: error: no match for call to '(less<A>) (A &)' stl_function.h:230:12: candidate is: stl_function.h:233:7: bool less<A>::operator()(const A &, const A &) const stl_function.h:233:7: candidate expects 2 arguments, 1 provided I am compiling with g++ 4.5 with the --std=c++0x flag. The error goes away if I do not define BOOST_RESULT_OF_USE_DECLTYPE (but I need this define for other things). Am I doing something wrong or is this a bug? Thanks, Nate.
Nathan Ridge wrote:
Am I doing something wrong or is this a bug?
You're not doing wrong. This is caused by incorrect use of `result_of`. Changing the line 56 of boost/ptr_container/indirect_fun.hpp BOOST_DEDUCED_TYPENAME result_of< Fun( BOOST_DEDUCED_TYPENAME pointee<T>::type& ) >::type to BOOST_DEDUCED_TYPENAME result_of< const Fun( BOOST_DEDUCED_TYPENAME pointee<T>::type& ) >::type resolves the issue (`Fun` is changed to `const Fun`). Regards, Michel
Nathan Ridge wrote:
Am I doing something wrong or is this a bug?
You're not doing wrong. This is caused by incorrect use of `result_of`.
Changing the line 56 of boost/ptr_container/indirect_fun.hpp BOOST_DEDUCED_TYPENAME result_of< Fun( BOOST_DEDUCED_TYPENAME pointee::type& ) >::type to BOOST_DEDUCED_TYPENAME result_of< const Fun( BOOST_DEDUCED_TYPENAME pointee::type& ) >::type resolves the issue (`Fun` is changed to `const Fun`).
I still get the compiler error after making the change.
From the instantiation backtrace, the problematic result_of invocation is on line 108, not line 56 (but changing `Fun` to `const Fun` on line 108 doesn't help either).
Regards, Nate.
Nathan Ridge wrote:
You're not doing wrong. This is caused by incorrect use of `result_of`.
Changing the line 56 of boost/ptr_container/indirect_fun.hpp BOOST_DEDUCED_TYPENAME result_of< Fun( BOOST_DEDUCED_TYPENAME pointee::type& ) >::type to BOOST_DEDUCED_TYPENAME result_of< const Fun( BOOST_DEDUCED_TYPENAME pointee::type& ) >::type resolves the issue (`Fun` is changed to `const Fun`).
I still get the compiler error after making the change.
Oh sorry, I tested with the trunk version... Regards, Michel
Michel MORIN wrote:
This is caused by incorrect use of `result_of`.
Changing the line 56 of boost/ptr_container/indirect_fun.hpp BOOST_DEDUCED_TYPENAME result_of< Fun( BOOST_DEDUCED_TYPENAME pointee::type& ) >::type to BOOST_DEDUCED_TYPENAME result_of< const Fun( BOOST_DEDUCED_TYPENAME pointee::type& ) >::type resolves the issue (`Fun` is changed to `const Fun`).
The above is completely wrong. Sorry for the noise. Regards, Michel
On 25/02/2011 11:57, Thorsten Ottosen wrote:
On 2/25/2011 8:30 AM, Nathan Ridge wrote:
Hello,
The following code:
#include<boost/ptr_container/ptr_set.hpp> struct A { bool operator<(const A&) const; };
The compiler is pretty clear about it. Define
bool operator<( const A&, const A& );
Is that the infamous ternary operator<?
On 25/02/2011 08:30, Nathan Ridge wrote:
Hello,
The following code:
#include<boost/ptr_container/ptr_set.hpp> struct A { bool operator<(const A&) const; }; int main() { boost::ptr_set<A> s; return 0; }
gives the following compiler errors when compiling with BOOST_RESULT_OF_USE_DECLTYPE defined:
[...] It's a bug yes. File a ticket.
Hello,
The following code:
#include struct A { bool operator<(const A&) const; }; int main() { boost::ptr_set s; return 0; }
gives the following compiler errors when compiling with BOOST_RESULT_OF_USE_DECLTYPE defined: [...]
It's a bug yes. File a ticket.
I filed https://svn.boost.org/trac/boost/ticket/5232 Regards, Nate.
A similar error happens even with tr1 result_of (i.e. without defining BOOST_RESULT_OF_USE_DECLTYPE). Minimal test case (fails to be compiled): #include <boost/ptr_container/indirect_fun.hpp> template <typename T> struct my_less { bool operator()(T const& t1, T const& t2) const { return t1 < t2; } template <typename Sig> struct result; template <typename This, typename Arg> struct result<This(Arg, Arg)> { typedef bool type; }; }; int main (int argc, char* argv[]) { boost::void_ptr_indirect_fun<my_less<int>, int, int> f; return 0; } The error occurred in the code (at line 105 of ptr_container/indirect_fun.hpp) which determines the return type of unary function call operator of class boost::void_ptr_indirect_fun<my_less<int>, int, int>: result_of<my_less<int>(int&)>::type operator()( const void* r ) const {...} Since result_of<my_less<int>(...)> only works with two function parameters, this code does not compile. These issues, including OP's one, can be fixed by removing unary function call operator of class boost::void_ptr_indirect_fun (i.e. making it BinaryFunction). Hope this helps, Michel
Den 01-03-2011 21:30, Michel MORIN skrev:
The error occurred in the code (at line 105 of ptr_container/indirect_fun.hpp) which determines the return type of unary function call operator of class boost::void_ptr_indirect_fun<my_less<int>, int, int>:
result_of<my_less<int>(int&)>::type operator()( const void* r ) const {...}
Since result_of<my_less<int>(...)> only works with two function parameters, this code does not compile.
These issues, including OP's one, can be fixed by removing unary function call operator of class boost::void_ptr_indirect_fun (i.e. making it BinaryFunction).
The problem then is that we can't use the class with unary functions. Something that might already we be done by users. -Thorsten
Thorsten Ottosen wrote:
These issues, including OP's one, can be fixed by removing unary function call operator of class boost::void_ptr_indirect_fun (i.e. making it BinaryFunction).
The problem then is that we can't use the class with unary functions. Something that might already we be done by users.
So, how about adding void_ptr_indirect_binary_fun (and void_ptr_indirect_unary_fun)? Then we have void_ptr_indirect_fun (with unary and binary function call operators) void_ptr_indirect_unary_fun (with unary function call operator) void_ptr_indirect_biary_fun (with binary function call operator) and use void_ptr_indirect_binary_fun when wrapping comparators. Regards, Michel
On 3/3/2011 12:13 AM, Michel MORIN wrote:
Thorsten Ottosen wrote:
These issues, including OP's one, can be fixed by removing unary function call operator of class boost::void_ptr_indirect_fun (i.e. making it BinaryFunction).
The problem then is that we can't use the class with unary functions. Something that might already we be done by users.
So, how about adding void_ptr_indirect_binary_fun (and void_ptr_indirect_unary_fun)? Then we have void_ptr_indirect_fun (with unary and binary function call operators) void_ptr_indirect_unary_fun (with unary function call operator) void_ptr_indirect_biary_fun (with binary function call operator) and use void_ptr_indirect_binary_fun when wrapping comparators.
I was messing around with enable_if to see if we could detect the number of arguments. But I couldn't find a traits that does that yesterday ... now I see <boost/function_types/function_arity.hpp> could help. This way I think we can avoid instantiating result_of until it works. If only we had perfect forwarding and variadic templates, it would be so easy to write operator()(). -Thorsten
Thorsten Ottosen wrote:
I was messing around with enable_if to see if we could detect the number of arguments. But I couldn't find a traits that does that yesterday ... now I see
<boost/function_types/function_arity.hpp>
could help. This way I think we can avoid instantiating result_of until it works.
Note that you cannot use SFINAE based on template `Fun`'s arity since `Fun` is not a template parameter of void_ptr_indirect_fun's operator(). To avoid unnecessary instanciation of result_of, we might need to make operator() a function template and make its return type a dependent type of its template parameters. The following code works fine: #include <boost/static_assert.hpp> #include <boost/type_traits/is_void.hpp> /* ... */ template <typename Type, typename Dummy> struct make_lazy { typedef typename Type::type type; }; template <typename Fun, typename Arg1, typename Arg2 = Arg1> class void_ptr_indirect_fun { /* ... */ template <typename Dummy> typename make_lazy< boost::result_of<const Fun(const Arg1&)> , Dummy >::type operator()(const Dummy* r) const { BOOST_STATIC_ASSERT(boost::is_void<Dummy>::value); BOOST_ASSERT(r != 0); return fun( *static_cast<const Arg1*>(static_cast<const void*>(r)) ); } template <typename Dummy> typename make_lazy< boost::result_of<const Fun(const Arg1&, const Arg2&)> , Dummy >::type operator()(const Dummy* l, const Dummy* r) const { BOOST_STATIC_ASSERT(boost::is_void<Dummy>::value); BOOST_ASSERT(l != 0 && r != 0); return fun( *static_cast<const Arg1*>(static_cast<const void*>(l)) , *static_cast<const Arg2*>(static_cast<const void*>(r)) ); } /* ... */ }; /* ... */ Regards, Michel
Den 03-03-2011 14:39, Michel MORIN skrev:
Thorsten Ottosen wrote:
To avoid unnecessary instanciation of result_of, we might need to make operator() a function template and make its return type a dependent type of its template parameters.
The following code works fine:
Thanks. This is excellent. I have only made minor changes. The change is comitted to trunk ... if it goes well, then it can go to release. Check it out if you have the time. cheers -Thorsten
Thorsten Ottosen wrote:
The change is comitted to trunk ... if it goes well, then it can go to release. Check it out if you have the time.
Great! I looked at the code and test it with GCC 4.6. * For indirect_fun, make_lazy is not necessary because the return type of its operator() is already a dependent type. * For indirect_fun, pointee in result_of should not be removed. This broke test/indirect_fun.cpp when compiling with BOOST_RESULT_OF_USE_DECLTYPE. * <boost/static_assert.hpp> and <boost/type_traits/is_void.hpp> should be included even if BOOST_NO_SFINAE is defined. I attached a patch for fixing these problems. After applying this patch, the OP's code, my code with my_less comparator and test/indirect_fun.cpp all run fine (w/wo BOOST_RESULT_OF_USE_DECLTYPE). Thanks, Michel
Den 04-03-2011 08:37, Michel MORIN skrev:
Michel MORIN wrote:
I attached a patch for fixing these problems. After applying this patch, the OP's code, my code with my_less comparator and test/indirect_fun.cpp all run fine (w/wo BOOST_RESULT_OF_USE_DECLTYPE).
Ouch! Forgot to attach a patch.
Thanks. Applied to trunk. regards -Thorsten
participants (4)
-
Mathias Gaunard
-
Michel MORIN
-
Nathan Ridge
-
Thorsten Ottosen