Search code examples
c++templatesfriendforward-declaration

How to organize classes containing mixture of templates and friends?


I have two C++ classes such that:

  1. The first class contains a pointer to the second class and has template function that calls second class's public method through a pointer. The function is defined already in the class declaration, for the reason of being a template.
  2. The second class allows the first class to access its private members through friendship mechanism.

Given that, my question is: how do I organize the sources/headers/forward declarations for this situation? Whatever I tried, it just doesn't compile to an object file.

One sequence is this:

class Class2;

class Class1
{
        Class2 * c2;
public:
        template<typename T> T DoSomething(T& X)
        {
                c2->Func();
                return X;
        };

        void FuncFromClass1();

};

class Class2
{
        int data;
public:
        Class2() : data(0) {};
        void Func();
        friend void Class1::FuncFromClass1();
};

void Class2::Func()
{
        int i;
}

void Class1::FuncFromClass1()
{
        int j;
        c2 = new Class2;
        c2->data = 1;
}

Barks invalid use of incomplete type ‘class Class2’ because it doesn't recognize c2->Func();. The other one is:

class Class1;

class Class2
{
        int data;
public:
        Class2() : data(0) {};
        void Func();
        friend void Class1::FuncFromClass1();
};

class Class1
{
        Class2 * c2;
public:
        template<typename T> T DoSomething(T& X)
        {
                c2->Func();
                return X;
        };

        void FuncFromClass1();

}; 

void Class2::Func()
{
        int i;
}

void Class1::FuncFromClass1()
{
        int j;
        c2 = new Class2;
        c2->data = 1;
}

Doesn't recognize friend void Class1::FuncFromClass1();.

The compilation is tried as g++ -c -std=c++11 -Wall test.cpp.

Note I'd rather not make Class1 as entire friend, rather want to keep only one of its methods as a friend to Class2, if at all possible.

Also, I haven't tried the exact same example in Visual Studio in Windows, but saw an entirely isomorphic situation like the one described (within a bigger project) and no complaints came from VS as far as I recall. Is it unique to g++?


Solution

  • Move the implementation of the member function template where definition of Class2 is known.

    class Class2;
    
    class Class1
    {
       private:
          Class2 * c2;
       public:
    
          // Delcare, don't define
          template<typename T> T DoSomething(T& X);
    
          void FuncFromClass1();
    
    };
    
    class Class2
    {
       private:
          int data;
       public:
          Class2() : data(0) {};
          void Func();
          friend void Class1::FuncFromClass1();
    };
    
    // Define
    template<typename T>
    T Class1::DoSomething(T& X)
    {
       c2->Func();
       return X;
    };
    

    Note that the proposed solution is simple if both classes are defined in one .h file. If the classes are defined in separate .h files, things get a little bit more complex. You'll have to make sure that the .h file where Class1::DoSomething() is defined is #included in every .cpp file where you want to use Class1::DoSomething().