Opened 13 years ago

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

Download all attachments as: .zip

Change History (5)

comment:1 by Andrey Semashev, 13 years ago

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.

by Andrey Semashev, 13 years ago

Attachment: get_ptr_fix.patch added

The patch renames get_pointer function from Boost.Intrusive

comment:2 by Andrey Semashev, 13 years ago

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 by Steven Watanabe, 13 years ago

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 by Ion Gaztañaga, 12 years ago

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

Fixed for Boost 1.45 in release branch

Note: See TracTickets for help on using tickets.