2

I am trying to make my head around CRTP and C++20. Basically, I'd like to have static inheritance that can access the derived type's typedefs and using:

template <typename Derived>
class inherit
{
public:

    Derived& underlying()
    {
        return static_cast<Derived&>(*this);
    }

    Derived const& underlying() const
    {
        return static_cast<Derived const&>(*this);
    }
};

template <typename Derived>
class tester : public inherit<Derived>
{
public:
    using value_type = typename Derived::value_type;
};

class real : public tester<real>
{
public:
    using value_type = int;
};


int main()
{
    return 0;
}

This, as explained in some other questions on SO is not allowed as of C++14 (answers that I find refer to that standard and to C++11). My understanding is that there is no way in C++17 either (if my compiler is right).

What is the current status with C++20? Are there any better solutions with the upcoming standard?

senseiwa
  • 2,369
  • 3
  • 24
  • 47
  • 3
    related [CRTP: How to infer type of member to be used as return type?](https://stackoverflow.com/questions/50188172/crtp-how-to-infer-type-of-member-to-be-used-as-return-type/50188570#50188570) and [CRTP: why a difference between getting a nested type and nested method of the derived class?](https://stackoverflow.com/questions/51553479/crtp-why-a-difference-between-getting-a-nested-type-and-nested-method-of-the-de/51553677#51553677) (most likely a duplicate) Note that this has nothing to do with `using`, the problem is that `Derived` class is incomplete at that point – user7860670 Jan 22 '19 at 14:52
  • Yes, the problem is exactly that, but I don't know anything about this issue and the upcoming standard. – senseiwa Jan 22 '19 at 14:56
  • 6
    Literally nothing changes as far as I know. Maybe it will get even more complicated with modules. – user7860670 Jan 22 '19 at 14:57
  • Nothing in C++20 being discussed makes this work. But it's also hard to answer the question of if there are better solutions, since the code as presented doesn't actually do anything. – Barry Jan 22 '19 at 16:20

1 Answers1

5

No, it's still not allowed in C++20. And it will undoubtedly remain not being allowed in C++ so long as the derived class is incomplete until the base class template is finished being instantiated. Which will undoubtedly remain the way things are because what you want would require the compiler to compile the derived class to some degree before instantiating the base class template, and that degree of "look ahead" is just not practical. And can lead to infinite loops or other confused constructs, since derived class member declarations/definitions are expected to be able to access accessible base class declarations.

Consider the simple case of some iterator requirements. Iterators have to have a value_type (ignore the whole "iterator_traits" business for the moment; our intent is to use the default traits), which the derived class will provide. Our helper iterator CRTP base class will helpfully use the derived class value_type declaration to generate pointer, reference, and so forth. But the derived class's operator* needs to be able to return reference, which is inherited from the base class, which itself is dependent on compiling the value_type declaration in the derived class. So... which gets compiled first: the base class template instantiation or the derived class? It has to be one or the other; it can't be both at the same time.

The ultimate problem is that the CRTP is just not what we really want. What we really want is to be able to store a sequence of declarations/definitions in a centralized location, then inject them into a class as needed. IE: an actual mixin. Using inheritance of a template type that names the derived class is merely the closest tool the C++ language has to achieve that. But since inheritance and template instantiation were never intended to serve this need, there will naturally be warts associated with it.

So you will continue to have to rely on the typical alternative: using a "traits" class templated on the derived class type.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982