【问题标题】:Specify base class template parameter depending on the derived class fields [duplicate]根据派生类字段指定基类模板参数[重复]
【发布时间】:2020-09-12 17:06:34
【问题描述】:

我希望能够根据派生类中数据成员的数量将基类中数据成员的类型设置为尽可能小。因此,如果派生类的数据成员数为5,则基类的数据成员类型应为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;
}

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

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

提前致谢!

【问题讨论】:

  • 无关的,像begin__这样的名字是为实现保留的。
  • 看来您需要反思。当前的解决方案,即使你让它工作,如果你在Foo 中添加空行,也会失败。
  • 没有冒犯,但在我看来 XY 有问题。
  • @cigien 是的,我知道只是没有改变它
  • @StoryTeller-UnslanderMonica 我知道有人会告诉我 :) ... 这是我目前正在开发的小型图书馆:github.com/m-peko/bitflags。我试图避免指定每个标志的数据类型

标签: c++ templates c++17 crtp


【解决方案1】:

当您需要 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>;

【讨论】:

  • 只是一个侧面问题:是否有可能将每个F_AF_B 等的数据类型设置为使用min_t 计算的数据类型?
  • 我认为你必须重新考虑你的依赖关系,也许template &lt;auto... Vars&gt; struct MyWrapper {/**/}; 会更合适。
【解决方案2】:

您可以将静态变量放在单独的 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>> {};

【讨论】:

  • 只是一个侧面问题:是否有可能将每个F_AF_B 等的数据类型设置为使用min_t 计算的数据类型?
  • @NutCracker 为此添加了一种解决方案。也可以应用于 Jarods 的答案。
  • 谢谢。我真的从这两个答案中学到了很多东西。如果可以的话,我会再给你一个 +1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-22
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多