如何找到 child class 的最大可能大小

How to find the largest possible sizeof child class

给定一个 class,我想在编译时找到最大的 sizeof() 所有子 classes。在这种情况下,您需要正确定义 B::BIGGEST_TYPE_SIZE 的值,最好是在 class 本身中。

可以在单独的代码块中使用 std::max() 来完成此操作,如最后一行所示,但这是一些重复的代码且不优雅,因为我将不得不不断修改它更多 class 继承自 B.

我想要一个很好的可扩展解决方案。

struct B 
{
    static const int BIGGEST_TYPE_SIZE;
};

struct D1 : public B
{
    int i;
};

struct D2 : public B
{
    std::vector<int> vec;
};

struct D3 : public B
{
    std::string s;
};

const int B::BIGGEST_TYPE_SIZE = std::max(sizeof(D1), std::max(sizeof(D2), sizeof(D3)));

BIGGEST_TYPE_SIZE 的值应为“32”,因为 std::string

对此有什么优雅的解决方案吗? 模板越性感越好。 谢谢!

std::variant, it knows its size from the template arguments. Your best shot is also to use a variadic template. First, you implement the variadic max function template为例,那么你使用它:

template <typename ... Ts>
constexpr bool biggest_size_v = max(sizeof(Ts)...);

如果您要求自动获取 compile-time 处所有派生的 类 的列表。你不能。您仍然需要列出它们:

const int B::BIGGEST_TYPE_SIZE = biggest_size_v<D1, D2, D3>;

It is possible to do so in a separate chunk of code with the usage of std::max as shown in the last line, but it's some what duplicate code and unelegant, as I will have to continuously modify that line as more classes inherit from B.

I would like a nice scalable solution instead.

不幸的是,我不知道自动识别所有派生类型的方法(我不认为这是可能的)所以我担心您需要“随着更多 classes 继承不断修改该行表格 B".

在 LogicStuff 的回答中,您看到了一种简化该行的优雅方法,我还记得存在接收 std::initializer_listconstexpr 从 C++14 开始的 std::max() 版本) 所以你也可以写(但是 biggest_size_v 方式更好,恕我直言)

const int B::BIGGEST_TYPE_SIZE
   = std::max({sizeof(D1), sizeof(D2), sizeof(D3)});

避免多次 std::max() 调用。

有点跑题了,我想,但我建议你使用 semi-automatic 方法来检查 compile-time,即 B::BIGGEST_TYPE_SIZE 大于(或等于)sizeof() 所有派生类型(至少所有实例化的派生类型)。

如果您修改 B 添加带有 static_assert() 的构造函数(或启用 SFINAE,如果您愿意)

struct B 
 {
   static const int BIGGEST_TYPE_SIZE;

   template <std::size_t DerSize>
   B (std::integral_constant<std::size_t, DerSize>)
    { static_assert( DerSize <= BIGGEST_TYPE_SIZE, "!" ); }
 };

并添加一个继承自 B

的模板 C 结构
template <typename Der>
struct C : public B
 {
   C() : B{std::integral_constant<std::size_t, sizeof(Der)>{}}
    { }
 };

如果您将 Dx classes 修改为继承 B 通过 C<Dx> (因此使用 CRTP)

struct D1 : public C<D1>
 { int i; };

struct D2 : public C<D2>
 { std::vector<int> vec; };

struct D3 : public C<D3>
 { std::string s; };

你 auto-magically 在 B 构造函数中启用 compile-time 检查。

因此,如果您添加以下内容,例如 D4 class

struct D4 : public C<D4>
 { int a[42]; };

并且忘记修改 BIGGEST_TYPE_SIZE 初始化,在列表中添加 sizeof(D4),声明一个 D4 对象,你得到一个编译错误

D4 d4; // compilation error

下面是一个完整的编译示例

#include <vector>
#include <iostream>
#include <algorithm>

struct B 
 {
   static const int BIGGEST_TYPE_SIZE;

   template <std::size_t DerSize>
   B (std::integral_constant<std::size_t, DerSize>)
    { static_assert( DerSize <= BIGGEST_TYPE_SIZE, "!" ); }
 };

template <typename Der>
struct C : public B
 {
   C() : B{std::integral_constant<std::size_t, sizeof(Der)>{}}
    { }
 };

struct D1 : public C<D1>
 { int i; };

struct D2 : public C<D2>
 { std::vector<int> vec; };

struct D3 : public C<D3>
 { std::string s; };

struct D4 : public C<D4>
 { int a[42]; };

const int B::BIGGEST_TYPE_SIZE
   = std::max({sizeof(D1), sizeof(D2), sizeof(D3)}); // <-- sizeof(D4) forgotten !!!

int main ()
 {
   D1 d1;
   D2 d2;
   D3 d3;
   // D4 d4;  compilation error
 }