|
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