Search code examples
c++templatesmetaprogrammingforward-declarationdefault-arguments

Am I Allowed to Default a Template Argument in a Forward Declaration


So I'm trying to understand what's happening with Boost's ptree implementation.

In ptree.hpp basic_ptree is actually defined:

template<class Key, class Data, class KeyCompare>
class basic_ptree

In ptree_fwd.hpp there is what looks like a forward declaration of basic_ptree but with a new template argument default:

template < class Key, class Data, class KeyCompare = std::less<Key> >
class basic_ptree;

And finally in ptree_fwd.hpp ptree is typedef'd:

typedef basic_ptree<std::string, std::string> ptree;

This is a forward declaration then in ptree_fwd.hpp, right? So I am allowed to default a template argument in a forward declaration?


Solution

  • Yes, you can. But you can specify each default template argument only once.

    17.1/14

    The set of default template-arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are (dcl.fct.default).

    [ Example:

    template<class T1, class T2 = int> class A;
    template<class T1 = int, class T2> class A;
    

    is equivalent to

    template<class T1 = int, class T2 = int> class A;
    

    — end example ]

    And 17.1/16

    A template-parameter shall not be given default arguments by two different declarations in the same scope. [ Example:

    template<class T = int> class X;
    template<class T = int> class X { /* ... */ };  // error
    

    — end example ]

    ( Note, these are taken from the latest draft, but these rules haven't changed in recent years to my knowledge )

    If you want to be able to make use of the default arguments when only the declaration is know, you'd have to define them in the declaration. Above also answers the question that you asked in the comments:

    I feel like this gets really nasty really quick. What if I include 2 separate headers that include different defaults in their forward declarations? Or is that what you're addressing?

    If you did that your program would be ill-formed, as you are allowed to specify each default argument only once. Having two declarations, where one defines the default arguments and the other doesn't, does not really cause any problems because they are not in disagreement of eachother. It only means that if only the version without defaults is known, you'd have to specify all arguments when instantiating your template.

    My personal opinion would be to have only one declaration in a header that specifies the default template arguments, and then include that header wherever you need the declaration (and for the definition as well).