1

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!

NutCracker
  • 11,485
  • 4
  • 44
  • 68

2 Answers2

2

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>;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Just one side question: Is it somehow possible to set the data type of each `F_A`, `F_B`, etc. to be the one calculated with `min_t`? – NutCracker Sep 12 '20 at 21:39
  • I think you have to rethink your dependencies, Maybe a `template struct MyWrapper {/**/};` would be more appropriate. – Jarod42 Sep 13 '20 at 16:19
1

You could put the static variables in a separate Bar and let Foo inherit from that and Wrapper.

#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 = 0;
};

struct Bar {
    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__;
};

struct Foo : Bar, Wrapper<Bar> {};

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

Edit

To make F_A, F_B etc the selected type you could make it a template and instatiate it with int to get the type.

template <typename T>
struct Bar {
    static constexpr int begin__ = __LINE__;
    static constexpr T F_A = 0;
    static constexpr T F_B = 0;
    static constexpr T F_C = 0;
    static constexpr int end__ = __LINE__;
};

struct Foo : Bar<Wrapper<Bar<int>>::type>, Wrapper<Bar<int>> {};
super
  • 12,335
  • 2
  • 19
  • 29
  • Just one side question: Is it somehow possible to set the data type of each `F_A`, `F_B`, etc. to be the one calculated with `min_t`? – NutCracker Sep 13 '20 at 11:51
  • @NutCracker Added one solution for that. Could be applied to Jarods answer as well. – super Sep 13 '20 at 12:22
  • thanks. I really learned a lot out of both of these answers. Would give you one more +1 if I could – NutCracker Sep 13 '20 at 12:43