Reputation: 1147
Assume that one has two base classes Base1
and Base2
for which CRTP pattern is desired.
template <typename TDerived>
class Base1 {
};
template <typename TDerived>
class Base2 {
};
Now I would like to define a Derived
class such that it can be "parametrized" with a base one.
What would be the proper way to define it in C++ (C++17 if that matters)?
Below is a pseudo-C++ code
template <template <typename> class TBase>
class Derived : public TBase<Derived<TBase>> {}; // Recursion problem here
In reality such a derived class is an extension that is applicable to any base class.
Upvotes: 0
Views: 88
Reputation: 41770
From your comment:
The problem I think still exists.
Consider your own pseudo-code when fed to a compiler (and some addition):
template <typename TDerived>
struct Base1 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->a;
}
};
template <typename TDerived>
struct Base2 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->b;
}
};
template <template<typename> typename TBase>
struct Derived : TBase<Derived<TBase>> {
int a;
int b;
};
auto main() -> int {
auto b = Derived<Base1>{};
b.a = 1;
b.b = 2;
return b.get();
}
As you can see, that pattern is no problem for the compiler.
Now I would like to define a Derived class such that it can be "parametrized" with a base one. What would be the proper way to define it in C++ (C++17 if that matters)?
The way you posted it in the question is the right way, and works all the way to C++98.
You seem to state that there's a recursion problem here, but there is not.
You have a template class Derived
with a template template parameter Base1
. The compiler now "knows" that this type Derived<Base1>
. It is incomplete though, until the }
is reached.
Then the compiler sees the base, which is TBase<something>
, which is Base1
with some template parameter. Base1
need to be instantiated. The something
is Derived<Base1>
, which is an incomplete type.
The compiler then instantiate Base1
with Derived<Base1>
. During that process, you cannot use Derived<Base1>
in a way that it would require it to be complete.
Now that the base is instantiated and a complete type, the compiler finishes to instantiate Derived<Base1>
, now complete.
There is no recursion here.
Upvotes: 3