【问题标题】:How to find the largest possible sizeof child class如何找到子类的最大可能大小
【发布时间】:2019-10-23 18:20:56
【问题描述】:

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

可以使用std::max() 的用法在单独的代码块中执行此操作,如最后一行所示,但它有些重复代码和不优雅,因为我将不得不不断修改该行作为更多类继承自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

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

【问题讨论】:

    标签: c++ templates visual-c++ variadic-templates template-meta-programming


    【解决方案1】:

    std::variant 为例,它从模板参数中知道它的大小。最好的办法也是使用可变参数模板。首先,你实现the variadic max function template,然后你使用它:

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

    如果您要求在编译时自动获取所有派生类的列表。你不能。您仍然必须列出它们:

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

    【讨论】:

    • 或者只是std::max({sizeof(Ts)...})
    【解决方案2】:

    可以使用 std::max 在单独的代码块中执行此操作,如最后一行所示,但这是一些重复的代码和不优雅的代码,因为我将不得不不断修改该行类继承自 B。

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

    不幸的是,我不知道自动知道所有派生类型的方法(我认为这不可能)所以我担心你需要“随着更多类继承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() 调用。

    我想有点离题,但我建议您使用一种半自动的方式来检查编译时 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, "!" ); }
     };
    

    并添加一个模板 C 结构,该结构继承自 B

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

    如果您将 Dx 类修改为通过 C&lt;Dx&gt; 继承 B(因此使用 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; };
    

    您在 B 构造函数中自动启用编译时检查。

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

    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
     }
    

    【讨论】:

    • 虽然不幸的是,我将不得不在C++ std::max({sizeof(Ts)...}) 的行中写下您在ctor 中的静态断言解决方案确实很性感!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    • 2017-12-25
    • 1970-01-01
    • 2012-05-27
    • 2020-10-31
    • 2018-08-10
    • 2022-01-09
    相关资源
    最近更新 更多