2

I would like to inherit from a class template, but pass a member class of the inheriting class as a template parameter to the base. Is this even possible? Here's a minimal example.

template<typename T>
class Base { /* stuff involving T */ };

template <typename U>
class Derived : Base<typename Derived<U>::Member> {
public:
    class Member { /* stuff involving U */};
    /* stuff involving Member, Base<Member> and U */
};

This compiles fine until I try to create an instance of Derived (eg. Derived<int>) at which point g++ (7.2.0) tells me that I'm using an incomplete type.

In instantiation of ‘class Derived<int>’:
 error: invalid use of incomplete type ‘class Derived<int>’
 class Derived : Base<typename Derived<U>::Member> {
       ^~~~~~~

I can kind of see the problem: the instantiation of Base requires knowledge of Derived::Member, which hasn't yet been defined, but is there any way around this?

As an alternative, I could have Member outside Derived, but then I lose the advantages of having it as a member class (access to private and protected members of Derived, encapsulation of Member, etc...). I also considered making Member a member of Base instead, but logically, the contents of Member are specific to Derived and don't belong in the more general Base.

John
  • 207
  • 1
  • 7

1 Answers1

0

After some investigation, I've decided this is not possible. The closest thing that works is the Curiously Recurring Template Pattern (CRTP) described here: What is the curiously recurring template pattern (CRTP)?

As noted here Why this CRTP does not compile? and elsewhere, Derived is an incomplete type at the moment of the template instantiation of Base. Therefore Member is not known to exist, causing the error.

The closest to a solution I found was to move the functionality of Member into a separate, non-member, class (NonMemebr) and have Member inherit from that. That way everyone outside Base<NonMember> doesn't need to know that NonMember exists.

template<typename T>
class Base { /* Instance of T. */ };

namespace detail {
    class NotMember { /* Functionality I'd like to have in Member. */ };
}

template <typename U>
class Derived : Base<detail::NotMember> {
public:
    class Member : public detail::NotMember { /* Appropriate constructors. */ };
    /* Stuff involving U, Base<NotMember> and Member. */
};

This may not be the prettiest, but it does do what I want.

John
  • 207
  • 1
  • 7