Reputation: 83
I have been studying the CRTP lately and have come up of an idea to create a generic base template class using CRTP.
// Example.h
namespace A {
template <class TClass, typename T>
class Example {
public:
Example(T &someStruct) : m_someStruct_(someStruct)
{
}
~Example()
{
DoThis();
}
public:
void DoThis()
{
static_cast<TClass*>(this)->DoThat(m_someStruct_);
}
private:
T m_someStruct_;
};
}
// AsArgument.h
namespace A {
class AsArgument : public Example <AsArgument, SomeStruct> {
friend class Example <AsArgument, SomeStruct>;
private:
void DoThat(SomeStruct &someFun)
{
// Do something to someFun object.
// yehey(someFun);
printf("I want to do that! \n");
}
};
}
My goal is to use the base class object to access the derived class' functions and at the same time, separate the base and derived's implementation by including only the base class' header file and forward declare the derived class as a template argument.
I know the basics of what I can do with incomplete types but I can't seem to find information about templates.
Is it valid to forward declare the class TDerived argument instead of including the header file?
// SomeFile.cpp
#include "Example.h"
class A::AsArgument; // Forward declare this instead of including the AsArgument.h header file
namespace B {
void SomeClass::DoSomething()
{
SomeStruct fun;
Example <AsArgument, SomeStruct> example(fun);
}
}
I am not sure if this is a good design in creating a generic base template class, but my goal after establishing the base class is to easily create derived classes out of it and define the base class implementation on compile time. It's actually some sort of a combination of RAII and CRTP.
I can actually achieve this by including the "AsArgument.h" file with "Example.h" but the separation between the base and the implementation is lost. And I keep getting compile error when I try to forward declare the AsArgument class (probably because of namespace issues I'm not fully aware of).
Any advise or is this kind of design even efficient and valid?
Upvotes: 3
Views: 1185
Reputation: 17704
I'm not really sure what the design goal is here, but the rules about incomplete types apply in the same way whether or not you're talking about templates, you just need to think about where the template is instantiated.
In your case, you are trying to avoid including AsArgument.h in SomeFile.cpp. However, you instantiate the Example class template with the AsArgument class. That means that when you compile SomeFile.cpp, that translation unit does not know anything about the AsArgument class (because it doesn't see its declarations in the .h file), only that it exists.
However, as you might expect, you can't do much with a class if you only know it exists. You can't even hold it by value, since you don't know its size. You can't use any of its interface. In your example, there is no way the compiler can know that AsArgument::DoThat even exists (it doesn't necessarily need to know what it does, that can be left for the linker). Remember that Example is being instantiated in SomeFile.cpp, so that's where the compiler will need to know that DoThat exists.
So you need AsArgument.h. With a normal class, you could just put the declaration in the .h file, and put the definitions (the implementation) in the .cpp file. But AsArgument is a template class, so you can't do that in general. You can only do this for templates if you are templated on a limited number of classes, known in advance, and are willing to explicitly template on all of them.
I can't comment too much on the bigger picture, because I don't know what you are trying to do. I'm not very confident that CRTP is even a fit for you. CRTP is useful for certain things but it's not really the first tool that I turn to. Actually, now that I think of it: I quite rarely use it. In most cases if I'm going to use template based polymorphism, I could just hold the "child" directly and skip the base entirely, in many cases I don't feel like the base buys me enough.
I'd recommend including any compiler errors you have in future SO questions. Good luck!
Upvotes: 1