Search code examples
c++c++14template-meta-programmingcrtp

Is it possible to access child types in c++ using CRTP?


I have this toy example,

template <typename TChild>
struct Base {
    template <typename T>
    using Foo = typename TChild::template B<T>;
};

struct Child : Base<Child> {
    template <typename T>
    using B = T;
};


using Bar = Child::Foo<int>;

which fails to compile. The intention is that I have a parent class that provides type computations based on members of the child class. The child class is provided via CRTP. However the line

using Foo = typename TChild::template B<T>;

fails to compile:

<source>: In instantiation of 'struct Base<Child>':
<source>:16:16:   required from here
<source>:13:11: error: invalid use of incomplete type 'struct Child'
   13 |     using Foo = typename TChild::template B<T>;
      |           ^~~
<source>:16:8: note: forward declaration of 'struct Child'
   16 | struct Child : Base<Child> {
      |        ^~~~~

Am I being naive in expecting such a construct to work?

Failing code at https://godbolt.org/z/5Prb84


Solution

  • Let me post another way to do it:

    template<typename TChild, class T>
    struct GetB {
        using Type = typename TChild::template B<T>;
    };
    
    template<typename TChild>
    struct Base {
        template<typename T>
        using Foo = typename GetB<TChild, T>::Type;
    };
    
    struct Child : Base<Child> {
        template<typename T>
        using B = T;
    };
    

    I don't have a language-lawyer-type explanation why this works, but it should be related to having an additional level of indirection. When a compiler sees

    using Foo = typename TChild::template B<T>;
    

    it can (and will) check and complain right at this point that an incomplete type is used. However, when we wrap access to B<T> into a function or a struct,

    using Foo = typename GetB<TChild, T>::Type;
    

    then we're not accessing internals of TChild at this point, we're just using the name of it, which is fine.