Search code examples
c++templatesmetaprogrammingforward-declarationdefault-arguments

How do I forward declare a template type that has been forward declared elsewhere with a defaulting


So the excellent answer to this question states that you can default template types in a forward declaration, however:

You can specify each default template argument only once

This is more fully specified in the linked question, but Boost's Property Tree stuff works with the ptree type:

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

But the basic_ptree class is defined like this:

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

The only reason the ptree typedef is defined with only 2 template parameters is that before it's typedef there is the forward declaration:

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

This brings me to my actual question. I need to pass around a ptree. But I don't want to include Boost in my headers. This means that I'll have to forward declare. But I can't match the defaulted forward declaration because the default can only be declared once.

How can I write a forward declaration and forward typedef that depends upon the defaulting in another headers forward declaration?

I'm currently doing this, but that means I'm not forward typedef'ing, I'm making a new typedef:

template <class Key, class Data, class KeyCompare> class basic_ptree;
typedef basic_ptree<std::string, std::string, std::less<std::string>> ptree; 

For the sake of consistency I want to depend on the same defaulted forward declaration of basic_ptree that the original ptree typedef depended upon.


Solution

  • The short answer is that you can't. You either have to guarantee somehow that the other declaration will never be included so you can specify your own default, or you need to depend on that other declaration.

    But I get the feeling this is an XY problem, for the following statement:

    But I don't want to include Boost in my headers.

    Why not? Your code is obviously dependent on Boost's ptree, so anyone working with your code would have to have Boost installed anyway. If you want your declarations to also compile when Boost isn't installed, there are several options:

    • Make sure you exclude the bits that use ptree using preprocessor directives (#if/#endif blocks)
    • Use C++17's __has_include() to test for the existence of <boost/property_tree/ptree.hpp>, and then either include it if it exists, or declare your own ptree if it doesn't.