Question

Is it possible to forward declare a class that uses default arguments without specifying or knowing those arguments?

For example, I would like to declare a boost::ptr_list< TYPE > in a Traits class without dragging the entire Boost library into every file that includes the traits. I would like to declare namespace boost { template<class T> class ptr_list< T >; }, but that doesn't work because it doesn't exactly match the true class declaration:

template < class T,
    class CloneAllocator = heap_clone_allocator,
    class Allocator = std::allocator<void*>
    >
class ptr_list { ... };

Are my options only to live with it or to specify boost::ptr_list< TYPE, boost::heap_clone_allocator, std::allocator<void*> in my traits class? (If I use the latter, I'll also have to forward declare boost::heap_clone_allocator and include <memory>, I suppose.)

I've looked through Stroustrup's book, SO, and the rest of the internet and haven't found a solution. Usually people are concerned about not including STL, and the solution is "just include the STL headers." However, Boost is a much more massive and compiler-intensive library, so I'd prefer to leave it out unless I absolutely have to.

Was it helpful?

Solution

Any compilation unit that uses your facility that forward-declares boost stuff will need to include the boost headers anyway, except in the case that you have certain programs that won't actually use the boost part of your facility.

It's true that by forward-declaring, you can avoid including the boost headers for such programs. But you'll have to manually include the boost headers (or have an #ifdef) for those programs that actually use the boost part.

Keep in mind that more default template parameters could be added in a future Boost release. I'd advise against this route. What I would consider, if your goal is to speed compile times, is to use a #define to indicate whether the code using that boost library should be disabled. This way you avoid the forward declaration hassle.

OTHER TIPS

Yes. Default template arguments may be specified any time, anywhere, so long as the declarations don't conflict with each other. They are ultimately merged together from the various declarations.

Even this is legal:

template< class A, class B, class C = long >
class X;

template< class A, class B = int, class C >
class X;

template< class A = short, class B, class C >
class X { };

A similar example is given in §14.1/10. According to that paragraph, function default arguments behave similarly.

Good luck on getting the forward declaration to behave itself and not barf on everything!

I don't think you can forward declare a template with default arguments unless the library in question provided its own forward declaration header. This is because you can't respecify the default arguments (even if they match... gcc will still report “error: redefinition of default argument”).

So to the best of my knowledge the solution is for the library to supply a forward declaration header Foo_fwd.h:

#ifndef INCLUDED_Foo_fwd_h_
#define INCLUDED_Foo_fwd_h_
template<class T, class U=char> class Foo; // default U=char up here
#endif

and then the full implementation in Foo.h would be:

#ifndef INCLUDED_Foo_h_
#define INCLUDED_Foo_h_
#include "Foo_fwd.h"
template<class T, class U> class Foo { /*...*/ }; // note no U=char here
#endif

So now your code could use Foo_fwd.h as well... but unfortunately, since this approach requires modifying the original Foo.h to remove the default arguments this doesn't scale to 3rd party libraries. Maybe we should lobby the C++0x crew to allow equivalent respecification of default template arguments, à la typedefs...?

Well same issue here. But with STL.

If one of my header use eg. std::vector then I have to include the entire header. From this time every time I include my header even if my source code does not refer to std::vector at all the header gets included along with my header. If you include this header in lots of place that will mean lots of overparsing.

So I forward declared the std::vector and used std::vector* 's but my code don't want to compile due to the default arguments. If I place the default arguments in my header then the compiler refuses to compile the stl header due to the default argument respectification.

What I'm trying to do in this situation is creating my own Vector class that adapts the std::vector and forwards every method call to it. Probably this could solve the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top