Opened 7 years ago

Closed 7 years ago

#3840 closed Bugs (fixed)

Boost.Intrusive conflicts with Boost.Bind + smart pointers

Reported by: andysem Owned by: igaztanaga
Milestone: Boost 1.45.0 Component: intrusive
Version: Boost 1.41.0 Severity: Problem
Keywords: get_pointer bind mem_fn intrusive Cc:


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<
    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();

    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 andysem 7 years ago.
The patch renames get_pointer function from Boost.Intrusive

Download all attachments as: .zip

Change History (5)

comment:1 Changed 7 years ago by andysem

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 7 years ago by andysem

The patch renames get_pointer function from Boost.Intrusive

comment:2 Changed 7 years ago by andysem

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 7 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 igaztanaga

  • Milestone changed from Boost 1.42.0 to Boost-1.45.0
  • Resolution set to fixed
  • Status changed from new to closed

Fixed for Boost 1.45 in release branch

Add Comment

Modify Ticket

Change Properties
Set your email in Preferences
as closed The owner will remain igaztanaga.
The resolution will be deleted. Next status will be 'reopened'.

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

Note: See TracTickets for help on using tickets.