C++ template friend declaration for known class name nested in any other

Viewed 112

Good evening.

I have the following problem in writing some generic code (in C++11 at least):

Consider a class named I that may be nested in various classes A, B,...,N:

class A
{
protected:
  friend class I;
  class I
  {
  } i;
};

class B
{
protected:
  friend class I;
  class I
  {
  } i;
};

etc.

Actually I is a kind of interface tool, automatically inserted in various user classes A...N. Don't care of the reason to do that...

Then there is a specific class Z and the goal is to declare any I as friend of Z, so that any I and nothing else can use Z, whatever class A...N (defined later) the I will be nested in.

If I declare this way:

class Z
{
  friend class A;   // <--- but I don't want to have to know this one
  friend class I;
private:            // creation and use of Z are restricted to tools like I
  Z();
  // other methods
};

Then it works for A::I only:

From A::I::some_function() it is possible to build and use a Z, but not from B::I nor any other in B...N.

Without the friend class A;, none of the I can access Z.

  • How to get it generic ?

I'm looking for a way to write a template friend declaration granting the access for any X::I where X is the template parameter.

And not a template parameter for I of course, since I is not a template.

Of course I do not want to grant access to any class X so that any X::I can access Z too !

The following does not work:

class Z
{
  template< class X>  friend class X::I;
  ...
};

=> error: 'I' is not a member of 'X'
from gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)

Any idea of the correct syntax ? I did not find that use case in the reference...

Thanks a lot, Kind regards.

================= added on Aug. 16 : Precisions:

The I exists durably as part of the A (or other) while the Z is a tool living only during a particular operation of the I, that may be repeated, then a new Z is created, used then deleted everytime as a local of a method of I.

Also the Z has a consequent payload and I don't want to make it a permanent part of every object embedding a I. For instance by making Z inherited by I.

1 Answers

You can probably achieve what you're trying to do by making I inherit Z, and make Z an abstract base class (so it can't be accessed directly).

Something similar to:

class Z
{
    virtual void __() = 0;
  public:
    virtual ~Z() = default;
    void method() { std::cout << "Method from Z" << std::endl; }
};

class A
{
    friend class I;
  
  public:
    class I : public Z
    {
        void __() final {}
      public:
        static Z *make_z();
    } i;
};

Z *A::I::make_z()
{
    return new I();
}

int main()
{
    Z *z = A::I::make_z();
    z->method();
    
    return 0;
}
Related