Assume that I have the following bunch of files:
Generic.h: Complicated template class
#pragma once
template<typename K, typename V, template<typename Key, typename Value, typename ...> typename C>
struct GenericMap
{
C<K, V> key;
};
Special.h: Define fully specialized version of mentioned template class, simplifying the ease of use.
#pragma once
#include "Generic.h"
#include <string>
#include <map>
typedef GenericMap<std::string, int, std::map> SpecialMap;
Client.h: Client that uses SpecialMap
and define forward declaration.
#pragma once
class SpecialMap; // Wrong forward declaration
struct Client {
Client();
SpecialMap* map;
};
Client.cpp: Clients code might know Generic.h
and Special.h
#include "Client.h"
#include "Special.h"
Client::Client()
{
map["343"] = 2;
}
main.cpp:
#include <Client.h>
int main(int argc, char**args) {
Client c;
return 0;
}
GenericMap
represents a template class that has no forward declaration. For some users a fully specialized version SpecialMap
of GenericMap
should suffices, where for the ease of use a typedef
is used.
Now Client
uses internally SpecialMap
, but the header file should only declare a forward declaration for SpecialMap
.
Unfortunately, the following files will not compile. Somehow the posted forward declaration will suffice. What will be the correct one?
I'm sorry for the long listings, but it was the smallest non-working example I could think of.
Forward Declaration refers to the beforehand declaration of the syntax or signature of an identifier, variable, function, class, etc. prior to its usage (done later in the program). In C++, Forward declarations are usually used for Classes.
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! Save this answer.
To write a forward declaration for a function, we use a function declaration statement (also called a function prototype). The function declaration consists of the function header (the function's return type, name, and parameter types), terminated with a semicolon. The function body is not included in the declaration.
Generally you would include forward declarations in a header file and then include that header file in the same way that iostream is included.
In the comments you clarified that you were not actually referring to C++ specialization. You were asking merely about the typedef:
typedef GenericMap<std::string, int, std::map> SpecialMap;
And that's pretty much the end of the story. This declares SpecialMap
to be a typedef
, a type alias. Any translation unit that needs to use SpecialMap
needs to include this type definition. And only this definition. Nothing else needs to be done. It does not need to be declared in any other way. It is an alias. A search/replace of the typedef
alias with its underlying type produces the same exact results. A typedef
declared in one translation unit is visible only in that translation unit. There are no short-cuts for other translation units to import the typedef
into their scope.
In your Client.h:
#include <Special.h>
That's where you defined this typedef
, and that's the only way to pull in this definition.
However, this may also be the case where the typedef
is a part of a larger header file, and it is desirable to pull in just the typedef, separately. This could be done with a header file containing only:
#include <string>
#include <map>
template<typename K, typename V,
template<typename Key, typename Value, typename ...>
typename C> struct GenericMap;
typedef GenericMap<std::string, int, std::map> SpecialMap;
This would be the bare minimum needed to define the typedef
alias. Anything that actually needs to use it, will need to #include
not just this header file, but also your Generic.h
header, which actually defines the GenericMap
template class, that's only forward-declared here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With