根据派生的 class 字段指定基础 class 模板参数

Specify base class template parameter depending on the derived class fields

我希望能够根据派生 class 中数据成员的数量,将基 class 中数据成员的类型设置得尽可能小。因此,如果派生 class 中的数据成员数为 5,则基 class 中的数据成员类型应为 std::uint8_t.

这是我已经尝试过的方法:

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

这显然不起作用并且无法编译,因为 Foo class 在 Wrapper class 定义时未完全指定。

有没有人对如何做到这一点有更好的想法,或者是否有可能?

提前致谢!

当您需要 CRTP 中的完整类型时,解决方法是不使用 CRTP :),而是使用另一种方式进行常规继承:

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>;

您可以将静态变量放在一个单独的 Bar 中,让 Foo 继承它和 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;
}

编辑

要使 F_AF_B 等成为所选类型,您可以将其设为模板并使用 int 实例化以获取类型。

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>> {};