How to forward declare a C++ template class?
Solution 1:
This is how you would do it:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings;
template<typename Type, typename IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
Note that the default is in the forward declaration and not in the actual definition.
Solution 2:
You can declare a templated class whose definition states the default arguments, but any time you reference the class you must include all its arguments until the definition is introduced.
eg. Let's use std::vector
without including it (the second argument of std::vector
is defined with a default):
namespace std
{
template<typename, typename>
class vector;
}
#include <iostream>
template <typename S, typename T>
void Foo (const std::vector<S,T> & vector)
{
std::cout << "do vector stuff, eg., display size = "
<< vector.size() << std::endl;
}
template <typename T>
void Foo (const T & t)
{
std::cout << "do non-vector stuff..." << std::endl;
}
We can then use it without including the vector, eg.:
int main ()
{
Foo(3);
}
...Or we can use it with std::vector
, eg.:
#include <vector>
// Now the compiler understands how to handle
// std::vector with one argument
// (making use of its default argument)
int main ()
{
Foo(std::vector<int>(3));
}
I haven't checked the standards, but this works on clang
/gcc
with -std=c++98
up to -std=c++17
, so if it's not officially a standard then it looks to be unofficially so.
Solution 3:
You can declare default arguments for a template only for the first declaration of the template. If you want allow users to forward declare a class template, you should provide a forwarding header. If you want to forward declare someone else's class template using defaults, you are out of luck!
Solution 4:
My answer complements the others as the solution I found actually mitigates the need for a template class forward declaration by creating a new type when all parameters are known (or provided as default) so that this new type, than you can forward declare, is not a template anymore:
template<typename Type=MyDefault, typename IDType=typename Type::IDType>
class MappingsGeneric
{
...
};
class Mappings : public MappingsGeneric<> {};
You can then class Mappings;
. I know that this solution doesn't apply everywhere but it did in my use case as I only used templates for high-performance dependency injection for non-virtual methods in a unit test context.