Search code examples
c++templatesc++17crtp

Specify base class template parameter depending on the derived class fields


I want to be able to set the type of a data member in a base class to as smaller as possible depending on the number of data members in the derived class. So, if the number of data members in the derived class is 5, type of data member in base class should be std::uint8_t.

Here is what I have tried already:

#include <iostream>

template <std::size_t N>
struct min {
    using type = typename std::conditional_t<
        (N <= 8), std::uint8_t,
        typename std::conditional_t<
            (N <= 16), std::uint16_t,
            typename std::conditional_t<
                (N <= 32), std::uint32_t, std::uint64_t
            >
        >
    >;
};

template <std::size_t N>
using min_t = typename min<N>::type;

template <typename CrtpT, typename T = min_t<CrtpT::end__ - CrtpT::begin__ + 1>>
struct Wrapper {
    T a;
};

struct Foo : Wrapper<Foo> {
    static constexpr int begin__ = __LINE__;
    static constexpr int F_A = 0;
    static constexpr int F_B = 0;
    static constexpr int F_C = 0;
    static constexpr int end__ = __LINE__;
};

int main() {
    Foo foo;
    std::cout << static_cast<unsigned>(foo.a) << std::endl;
    return 0;
}

This obviously does not work and does not compile since the Foo class is not fully specified at the moment of Wrapper class definition.

Does anyone have any better idea on how to do this or is it possible at all?

Thanks in advance!


Solution

  • Workaround when you need complete type in CRTP is to not use CRTP :), but regular inheritance the other way:

    template <typename T, typename U = min_t<T::end__ - T::begin__ + 1>>
    struct Wrapper : T {
        U a;
    };
    
    struct FooImpl {
        static constexpr int begin__ = __LINE__;
        static constexpr int F_A = 0;
        static constexpr int F_B = 0;
        static constexpr int F_C = 0;
        static constexpr int end__ = __LINE__;
    };
    
    using Foo = Wrapper<FooImpl>;