0

I have the following classes in the following files:

    // Tensor.hh
    template <class T>
    class Tensor {
        /* declarations */
    }

    // Tensor.cpp
    #include "Tensor.hh"
    // Implementation of Tensor.hh

    // Kernel.hh
    #include "Tensor.hh"
    template <class T>
    class Kernel : public Tensor<T> {
       /* declarations */
    }

    // Kernel.cpp
    #include "Kernel.hh"
    // Implementation of Kernel.hh

Is it possible to use a pointer to "Kernel" as parameter of a "Tensor" method? Something like:

    template <class T>
    void Tensor<T>::foo(Kernel<T>* kernel) {
        // Do something...
    }
  • Have you tried it? – alter_igel May 11 '21 at 14:01
  • 1
    Yes, it is possible. Did you get an error when you tried? Did you `#include "Kernel.hh"` in the file you tried to define the function in? – NathanOliver May 11 '21 at 14:01
  • With the appropriate includes/forward declaration is possible. Whether this is a good idea, well.... probably isn't it's a cyclic dependecy between classes, which are better avoided. – al3c May 11 '21 at 14:02
  • 1
    The implementation of class/function templates has to be visible to the users of those templates. So you can't have separate cpp files for the implementation unless you expect your users to directly `#include` those cpp files. – Kevin May 11 '21 at 14:04
  • Not sure if this will actually come up for you or not, but [standard link](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) about potential pitfalls of splitting class template definitions into header and source files. – Nathan Pierson May 11 '21 at 14:10

3 Answers3

0

Yes it is possible. In your Tensor.cpp you will have to include #include "Kernel.hh", and in your Tensor.hh you will have to add a forward declaration:

template<typename>
class Kernel;

Usually I would really avoid forward declaring template classes, and I would avoid circular dependencies. Sometimes they are not avoidable, but sometimes yes.

Another solution would be to simply implement foo as a free function in another header:

void foo(Tensor<T>& tensor, Kernel<T>* kernel) {
    // ...
}

That way you break the circular dependency, and you get bonus encapsulation.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
0

I think you need to use forward declaration of the class Kernel. I could compile following:

 template <class T>
    class Kernel;


 template <class T>
    class Tensor {
        /* declarations */
     void foo(Kernel<T>* kernel);
    };

 template <class T>
    class Kernel: public Tensor<T> {
    };

ivan.ukr
  • 2,853
  • 1
  • 23
  • 41
0

The implementation of your class templates needs to be visible to your users. So it's best to put the implementation directly in the header file.

// Forward declare Kernel<T> so Tensor<T> can know about it for foo()
template<typename T>
class Kernel;

// Define Tensor<T>
template<typename T>
class Tensor {
    void foo(Kernel<T>* kernel);
    ...
};

// Define Kernel<T>
template<typename T>
class Kernel : public Tensor<T> {
    ...
};

// Define Tensor<T>::foo here since Kernel<T> needs to be defined
// for it to do anything meaningful with it
template<typename T>
void Tensor<T>::foo(Kernel<T> *kernel) {
    // Do something...
}
Kevin
  • 6,993
  • 1
  • 15
  • 24