IBM Z and LinuxONE - Languages - Group home

Introduction to the C++11 feature: extended friend declaration

  

The extended friend declaration feature is newly introduced in the C++11 standard. In this article, I will introduce this feature and provide some examples on how to use this feature.


Firstly, let's see why this feature is added into C++11. Before C++11, an elaborated-type-specifier cannot be used in a template type-parameter. For example:


template <class T> class A {

friend class T; // Error in C++98, using template type-

// parameter 'T' after 'class'

};


In this case, if you want to declare a class that is a template parameter as a friend, the compiler issues an error.


However, according to the C++ standard, an elaborated-type-specifier must be used in a friend declaration for a class, which means, that the class-key of the elaborated-type-specifier is required.


With these requirements, you cannot declare a class that is a template parameter as a friend. However, more and more programmers complain about this restriction and think it would be more convenient if they can declare a template parameter as a friend.


So the C++11 standard added the extended friend declaration feature to address this issue. With this feature, the class-key is no longer required in the context of friend declarations. See the following example:

template <class T> class A {

friend T; // OK in C++11

};


This new syntax differs from the C++98 friend class declaration syntax, where the class-key is necessary as part of an elaborated-type-specifier. For example:

class A;

class B;


class X {

friend class A; //OK in both C++98 and C++11

friend B; //Error in C++98 for missing the class-

//key; OK in C++11

};


Another benefit of this feature is that in addition to functions, classes, and template parameters, you can also declare basic types as friends. The following example can be successfully compiled under C++11:


class C;

template <typename T> class A {

friend T;

};


A<C> rc;

A<int> Ri;


In this example, you can declare the template parameter T as a friend of class A, and you can use the basic type int in friend declarations.


This feature also introduces a new name lookup rule for friend declarations. If a friend class declaration does not use an elaborated-type-specifier, then the compiler also looks for the entity name in scopes outside the innermost namespace that encloses the friend declaration. Consider the following example:


struct T { };


namespace N {

struct S {

friend T; // OK in C++11

};

}


In this example, if this feature is in effect, the friend declaration statement does not declare a new entity T, but looks for T in the scope outside namespace N. If no T is found, the compiler issues an error.


Some programmers take it for granted that the simple-type-specifier form (without the class-key) have the same meaning as the elaborated-type-specifier form, and thus treat them with no difference. However, the truth is, unlike the elaborated-type-specifier form, the simple-type-specifier form cannot declare a new entity but must refer to an existing declaration.


For example,

class X {

friend D; // Error in C++98 for missing the class-key.

// Error in C++11 for lookup failure

friend class D; // OK in both C++98 and C++11;

// Declares a new entity class D

};


You can also declare typedef names as friends, but you cannot use an elaborated-type-specifier in the friend declaration. For example:

class Derived;

typedef Derived D;


class Sibling;

typedef Sibling S;


class Base{

public:

friend D; //Error in C++98; OK in C++11

friend class S; //Error in both C++98 and C++11

};

 

From the author: Thanks Jia Lei Ma and Xiao Feng Guan for their effort reviewing this blog.