4

For some reasons, I'd like to write code like this:

template<class T>
class C : public T
{
friend class T;
};

I think the code is clear. I want to have a class template which defines a class derived from the class passed to it as the template parameter, and to make things a little more complex, I'd like to define the base class as friend of the derived one. The code seems to be OK with MSVC compiler, but GNU C++ compiler complains a lot. What should I do to have the desired functionality?

modjtabaf
  • 43
  • 4
  • 4
    why friend if you are deriving from it? – Nim Oct 26 '11 at 08:25
  • 1
    What does GCC say, specifically? – Oliver Charlesworth Oct 26 '11 at 08:25
  • 1
    @Nim: for example you might be using CRTP to implement simulated dynamic binding, and you want the equivalent of a private virtual function. That is to say, a function that is called from the base class but doesn't need to be part of the public interface of `class C`. You can say, "well, it doesn't need to be private, just don't permit the plebs to use it", which is true, but some people get very agitated when you tell them that (aside from disabling default copies) access modifiers in C++ are a complete waste of time and you should just make everything public always ;-) – Steve Jessop Oct 26 '11 at 10:09
  • @Nim: I'd like to use CRTP as mentioned by Steve Jessop. – modjtabaf Nov 03 '11 at 17:56
  • @OliCharlesworth: It complains about incorrect usage of friend keyword, something like a missing class-key. – modjtabaf Nov 03 '11 at 17:58
  • @SteveJessop: I can't understand what do you mean when you say this "well, it doesn't need to be private, just don't permit the plebs to use it". How could it be done? by using 'protected' keyword instead of 'private'? – modjtabaf Nov 03 '11 at 18:00
  • @modjtabaf: make it public, and write in the documentation (or header file), "do not call this function except from the CRTP base class". Then anyone who calls it is in the same position as someone who pass a null pointer to `strlen` - UB, and it's their own fault for not RTFM. – Steve Jessop Nov 04 '11 at 10:37

1 Answers1

6

It is ill-formed, and is not valid C++ although it works in MSVC. The C++03 standard says this (7.1.5.3 §2):

3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the decla- ration the same way a simple-type-specifier introduces its type-name. If the identifier resolves to a typedef- name or a template type-parameter, the elaborated-type-specifier is ill-formed. [Note: this implies that, within a class template with a template type-parameter T, the declaration

       friend class T;

is ill-formed. ] If name lookup does not find a declaration for the name, the elaborated-type-specifier is ill-formed unless it is of the simple form class-key identifier in which case the identifier is declared as described in 3.3.1.

For this same reason you can't do things like friend class std::string; either, but you must befriend the std::basic_string with the template parameters.

However the new C++11 spec allows a new syntax for declaring friends, which simply is (11.3 §3 of N3242):

friend <typename-specifier>;

This new syntax allows you to do what you want (I don't know if MSVC yet supports this though):

template<typename T>
class C : public T
{
    friend T;
};
reko_t
  • 55,302
  • 10
  • 87
  • 77