Boost logo

Boost :

From: Ion Gaztañaga (igaztanaga_at_[hidden])
Date: 2006-06-13 10:34:41


Hi to all,

  There were some recent Shmem/Interprocess bug reports concerning header
ordering issues. I've investigated it a bit and I've come up with a
reduced test case that reproduces the problem that happens with the
static_pointer_cast() expression. Now that I have reduced the problem, I
don't know how to solve it so I need some expert ADL recommendation to
implement a "best practices" approach in my boost code.

  Imagine a container that can store raw pointers or smart pointers
pointer to a polymorphic class (or a container using an allocator that
defines its own "pointer" type). To avoid instantiations, it uses
static_pointer_cast to work only with base classes and avoid code bloat.
This is typical in node based containers like lists and trees.

  Then suppose a container factory that creates containers based on a
configuration. Here is the code:

////////////////////////////////////////
//containers.hpp header:
////////////////////////////////////////

namespace boost {
namespace dummy {

template<class Pointer>
class container
{
    Pointer ptr;
    public:
    void func()
    { static_pointer_cast<int>(Pointer()); }
};

} //namespace dummy {
} //namespace boost {

////////////////////////////////////////
//smart_ptr.hpp header:
////////////////////////////////////////

namespace boost {
namespace dummy {

template<class T>
class smart_ptr
{
};

template<class T, class U>
smart_ptr<T> static_pointer_cast(const smart_ptr<U> &u)
{ return smart_ptr<T>(); }

} //namespace dummy {
} //namespace boost {

////////////////////////////////////////
//container_factory.hpp header:
////////////////////////////////////////

namespace boost {
namespace dummy {

class container_factory
{
    public:
    template<class Container>
    static Container *create()
    {
       return new Container;
    }
};

} //namespace dummy {
} //namespace boost {

////////////////////////////////////////
//main.cpp:
////////////////////////////////////////

#include "container.h"
#include "smart_ptr.h"
#include "container_factory.h"

int main()
{
    using namespace boost::dummy;
    typedef container<smart_ptr<int> > my_container;
    my_container *cont = container_factory::create<my_container>();
    cont->func();
    return 0;
}

This code compiles in VC 7.1 and VC 8 but fails with gcc, complaining
the "there is no declaration for static_pointer_cast". If we change the
header order to:

#include "smart_ptr.h"
#include "container.h"
#include "container_factory.h"

This compiles fine because the static_pointer_cast definition is found
before the call. My first question is:

* Is this gcc error correct? Revising a bit ADL + template issues (a
fairly complicated logic that should be removed from C++, in my opinion)
I think that gcc is right.

* If gcc is correct, what is the implementor supposed to do? Every
templatized class header shouldn't include smart_ptr.h because smart_ptr
is unknown and it can even be a user-defined class.

* If this is correct, that is the user supposed to do? The user has
included all the headers, and he shouldn't know about the implementation
and internal dependency issues. It's really a mess for a user to start
guessing the correct header order. And this is only a simple dependency,
imagine a fairly more complicated approach, it would be really a nightmare.

So the question is, how should I write my library to take advantage of
ADL without creating such header dependency problems? Should I avoid ADL
and require static_pointer_cast overloads in boost namespace for a user
class defined in a different namespace?

I must have missed something, because otherwise, I would find ADL really
useless as a robust customization point. Any expert willing to help?

Regards,

Ion


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk