Modify

Opened 8 years ago

Closed 7 years ago

#3840 closed Bugs (fixed)

Boost.Intrusive conflicts with Boost.Bind + smart pointers

Reported by: Andrey Semashev Owned by: Ion Gaztañaga
Milestone: Boost 1.45.0 Component: intrusive
Version: Boost 1.41.0 Severity: Problem
Keywords: get_pointer bind mem_fn intrusive Cc:

Description

The file intrusive/detail/utilities.hpp defines generic get_pointer function. Apparently, this function is in conflict with the same-named functions for smart pointers, such as intrusive_ptr, which breaks compilation of boost::bind. The following example shows the problem:

#include <boost/bind.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/intrusive/list.hpp>

namespace intrusive = boost::intrusive;

typedef intrusive::list_base_hook<
    intrusive::link_mode< intrusive::auto_unlink >,
    intrusive::tag< struct MyStructTag >
> ListHook_t;

struct MyStruct :
    public ListHook_t
{
    void foo() {}

    friend void intrusive_ptr_add_ref(MyStruct*) {}
    friend void intrusive_ptr_release(MyStruct*) {}
};

typedef intrusive::list<
    MyStruct,
    intrusive::base_hook< ListHook_t >,
    intrusive::constant_time_size< false >
> List_t;

int main(int, char*[])
{
    List_t structs;
    boost::intrusive_ptr< MyStruct > p = new MyStruct();
    structs.push_back(*p);

    boost::bind(&MyStruct::foo, p)();

    return 0;
}

The compilation fails at least with MSVC 7.1 and GCC 4.1.0, the error is as follows:

./ThirdParty/BOOST/boost/intrusive/detail/utilities.hpp: In instantiation of 'boost::intrusive::detail::smart_ptr_type<boost::intrusive_ptr<MyStruct> >':
./ThirdParty/BOOST/boost/bind/mem_fn_template.hpp:40:   instantiated from 'R boost::_mfi::mf0<R, T>::call(U&, const void*) const [with U = boost::intrusive_ptr<MyStruct>, R = void, T = MyStruct]'
./ThirdParty/BOOST/boost/bind/mem_fn_template.hpp:54:   instantiated from 'R boost::_mfi::mf0<R, T>::operator()(U&) const [with U = boost::intrusive_ptr<MyStruct>, R = void, T = MyStruct]'
./ThirdParty/BOOST/boost/bind/bind.hpp:246:   instantiated from 'void boost::_bi::list1<A1>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = boost::_mfi::mf0<void, MyStruct>, A = boost::_bi::list0, A1 = boost::_bi::value<boost::intrusive_ptr<MyStruct> >]'
./ThirdParty/BOOST/boost/bind/bind_template.hpp:20:   instantiated from 'typename boost::_bi::result_traits<R, F>::type boost::_bi::bind_t<R, F, L>::operator()() [with R = void, F = boost::_mfi::mf0<void, MyStruct>, L = boost::_bi::list1<boost::_bi::value<boost::intrusive_ptr<MyStruct> > >]'
1.cpp:33:   instantiated from here
./ThirdParty/BOOST/boost/intrusive/detail/utilities.hpp:113: error: no type named 'value_type' in 'class boost::intrusive_ptr<MyStruct>'
./ThirdParty/BOOST/boost/intrusive/detail/utilities.hpp:114: error: no type named 'value_type' in 'class boost::intrusive_ptr<MyStruct>'
./ThirdParty/BOOST/boost/intrusive/detail/utilities.hpp:115: error: no type named 'value_type' in 'class boost::intrusive_ptr<MyStruct>'

One side of the problem is that smart_ptr_type trait, which is used by get_pointer from Boost.Intrusive, incorrectly detects pointee type. It assumes the smart pointer has a value_type nested typedef, while the conventional typedef is element_type. I would suggest using pointee trait from pointee.hpp to get this type portably.

The other side of the problem is that get_pointer from Boost.Intrusive should not have been used by Boost.Bind in the first place, because it's defined in the private namespace boost::intrusive::detail. I guess, this happens because of some ADL-related problem. Perhaps there is a using directive somewhere that leads to this.

One possible solution of the problem is to simply remove get_pointer definition from Boost.Intrusive and use unqualified calls to get_pointer instead. The version of get_pointer for raw pointers is already available in the get_pointer.hpp header.

Attachments (1)

get_ptr_fix.patch (18.8 KB) - added by Andrey Semashev 8 years ago.
The patch renames get_pointer function from Boost.Intrusive

Download all attachments as: .zip

Change History (5)

comment:1 Changed 8 years ago by Andrey Semashev

As my local way of fixing the problem, I renamed the get_pointer from Boost.Intrusive and all references to it. Please, find the patch attached.

Changed 8 years ago by Andrey Semashev

Attachment: get_ptr_fix.patch added

The patch renames get_pointer function from Boost.Intrusive

comment:2 Changed 8 years ago by Andrey Semashev

Oh, I think I know why get_pointer from Boost.Intrusive was found. ListHook_t in my example derives from detail::generic_hook, which brings in the detail namespace into lookup.

comment:3 Changed 8 years ago by Steven Watanabe

I generally use compile-fail test cases like [source:/trunk/libs/units/test/fail_adl_detail.cpp@46171 fail_adl_detail.cpp] to make sure that ADL isn't going awry.

comment:4 Changed 7 years ago by Ion Gaztañaga

Milestone: Boost 1.42.0Boost-1.45.0
Resolution: fixed
Status: newclosed

Fixed for Boost 1.45 in release branch

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Ion Gaztañaga.
The resolution will be deleted.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.