Code Structure Analysis
Code Structure Analysis
Home| Services| C++ Grammar | Examples of Analysis | Contacts|

Templates as friends of C++ classes

Every programmer knows that class can be declared as friend of another class. This notation is very familiar. It is less known is that adding a friend specification creates a forward declaration for the friend class on the namespace level if this class is not defined yet. Look at the example:

2 void    F10(C1 &p1);
4 class C2
5 {
6     friend class C1;
7 };
9 void    F11(C1 **p1);

Here you see that parser issued a syntax error at the line 2 because the class C1 is not yet defined. On the contrary, the function prototype on the line 9 compiles fine because friend specification on the line 6 generated forward declaration for C1.

In some cases it is necessary to have access from the code of template to the data fields and methods of a class. The syntax for this is the following:

2 template <class p1> class  T1;
4 class C3
5 {
6     template <class p1> friend class T1;
7 };

Specification on the line 6 tells that all instantiations of template T1 will be friends of the current class. Line 2 contains forward declaration of the class template. If this line would be missing, this will not change anything. Friend specification will create forward declaration for this class template exactly in the same way as it was done for simple class in the previous example.

This notation may sound a bit strange and not really logical. Somebody might prefer to write it like this:

friend template <class p1> class T1;

But this will be against the C++ grammar. Compiler will issue a syntax error. For example Microsoft's C++ compiler issues a pair of unclear messages that do not give any clue on what is going on and what might be wrong. Here are pieces of the C++ grammar that are related to declaring class template as friend:

R227 TemplateDeclaration:  TemplateDeclarationHeader Declaration ;
R19 Declaration:  BlockDeclaration ;
R24 BlockDeclaration:  SimpleDeclaration ;
R31 SimpleDeclaration:  DeclTypeSpecifier ';' ;
R33 DeclTypeSpecifier:  DeclPrefix ;
R50 DeclTypeSpecifier:  DeclTypeSpecifier ElaboratedTypeSpecifier ;
R54 DeclPrefix:  typedef | friend ;
R95 ElaboratedTypeSpecifier:  ClassKey SimpleOrQualifiedId ;
R197 ClassKey:  struct |  union |  class ;

As you can see the possible forms of the friend specification are deeply dug in the grammar. Besides the formal rules, C++ standard tells in human language that friend prefix can be used only with elaborated type specifiers and not with other possible forms of declaration. Functions and function templates can also be friends.

When a friend specification is processed according to the grammar, the DeclTypeSpecifier is assembled first and it already contains the friend specifier inside. Only later on when the DeclTypeSpecifier is promoted into Declaration the TemplateDeclarationHeader is taken into account. This is how the C++ grammar is defined in the standard. Compilers only follow this grammar.

If you find this article useful or if you want to propose topic for a similar article, send us a note using the contacts page.