代码之家  ›  专栏  ›  技术社区  ›  jhufford

导出编译时常量,同时限制类可见性

  •  0
  • jhufford  · 技术社区  · 6 年前

    我正在使用一个pre-c++11编译器,我正在尝试“导出”一个常量,而不公开从中计算该常量的类。

    // A.hpp ----------------------
    struct A{
    ...
    };
    // B.hpp ----------------------
    struct B{
    ...
    };
    
    // Manager.hpp ------------------
    #include "Manager.hpp"
    template <size_t a, size_t b>
    struct StaticMax
    {
       enum { value = a>b ? a : b };
    }
    class Manager
    {
    public:
        static const size_t OverlayDataSize;
     ...
    };
    // manager.cpp ------------------
    #include "A.hpp"
    #include "B.hpp"
    // I want the following constant to be available to anyone
    // that includes Manager.hpp, but the classes A and B should not
    // be visible to anyone else except class Manager
    const size_t Manager::OverlayDataSize = StaticMax<sizeof(A),sizeof(B)>::value;
    
    // otherfile.hpp -------------------
    #include "Manager.hpp"
    struct OverlayData
    {
        // shared state goes here
        uint8 gameState;
        uint8 specificState[Manager::OverlayDataSize];
    };
    class NvRam
    {
        void Write(OverlayData& serializedState);
        ....
    }
    

    以上代码无法编译,导致:

    错误:_ manager::overlaydatasize'不是类型_ unsigned的有效模板参数 int_,因为它是一个非常量表达式

    从那以后已经很奇怪了 Manager::OverlaySize 最肯定的是 const 其值在编译时计算。但是根据 this 问题,如果 康斯特 声明及其定义不在同一位置,因此编译器不能将其用作常量。即使使用声明为 extern . 我可以使用一个联合(但随后是结构)以不同的方式计算最大大小 A B 不允许有构造函数),但这不是问题,我仍然无法在编译时导出该常量以使其在不公开结构的情况下可用。 给大家。当然,我可以通过使dataoverlay结构更加复杂并使用 new uint8[Manager::OverlayDataSize]; 在运行时,能够保持严格的分离。但我正在努力让它在编译时静态完成。

    那么如何在保持结构之间严格分离的同时“导出”编译时常量 以及用户 Manager ?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Ruifeng Xie    6 年前

    这里有一个(相当难看的)解决方案。

    核心问题是你只需要 A B ,这是常量,但您必须包含整个定义。解决方案是手动计算大小并将其写入所需的位置。

    但当 被修改了,所以我们应该以某种方式自动完成上面的工作。

    要实现这一点,您可以编写一个代码生成器,它会将类似这样的代码生成到头文件中:

    const size_t OverlayDataSize = /* the calculated size */;
    

    并在每次重建整个项目时调用该程序。(例如,通过编写makefile。)

    发电机可以 A.hpp B.hpp 包括,计算 max(sizeof(A), sizeof(B)) 运行一个 printf 或者类似于编写生成的代码的东西。其他源文件只应 #include 生成的源。

    因为C++没有一个模块系统(它可以让你隐藏一些内部实体)或者一个完整的元编程工具(它允许我们编写一些生成其他代码的代码),所以我只能想到这个实现这一点的相当丑陋的方法。但不管怎样,它应该起作用。