编译时:计算类型 X 的成员的 #(~N) 个并定义一个成员数组 [N]?

Posted

技术标签:

【中文标题】编译时:计算类型 X 的成员的 #(~N) 个并定义一个成员数组 [N]?【英文标题】:Compile-time: count #(~N) of members of type X and define a member array[N]? 【发布时间】:2020-12-08 04:15:43 【问题描述】:

有没有办法在编译时计算结构中的成员数(下例中的整数)并在同一个结构中定义一个相同大小的数组?使用 MACRO 或模板化结构而不是 int 类型就可以了。

struct A

    int myInts[numInts()];  // here numInts() == 2
    int a;
    char b;
    char c;
    int d;
    char e;
;

我觉得一些 constexpr hack 可能是可行的,但还没有找到解决方案。我需要的是创建一个数组,我可以在其中压缩所有成员的副本,并且该数组需要在编译时静态分配。成员的数量因结构而异,但数组应自动增长,以便为所有感兴趣的成员提供空间。更糟糕的是,数组需要在其他成员之前定义。

====== 编辑

似乎没有一个解决方案可以在不使整体结构设计过于复杂的情况下完成上述操作。相反,我需要手动指定数组大小。

【问题讨论】:

您可以在使用各种“使用结构化绑定的结构到元组”技巧定义结构后执行此操作 为什么要一个相同大小的数组?扩展您想要这个的原因,也许我们可以提供替代方案。 我需要一个紧凑的存储空间来存储结构中所有整数的副本(以及任何子结构成员中的任何整数),因为它们都作为连续的内存块从和复制到立刻。不能一起定义所有整数的原因是某些整数作为其他结构成员的子成员(即 struct substruct char a; int b;; 因此它们在内存中交错。结构可以有很多非 int 成员。 【参考方案1】:

这可以使用MAP-MACRO 和一些模板来解决。 您需要使用宏定义结构并将所有字段传递给它(例如DEFINE_STRUCT(A, int a, char b, ...))。通过在void(int a, char b, ...) 类型的辅助函数上应用递归模板,可以计算int(或您想要的其他类型)字段的数量。在每个字段后附加分号需要 MAP-MACRO。

#include <type_traits>
#include "map-macro/map.h" // https://github.com/swansontec/map-macro, we need the `MAP` macro


// Count how many arguments of Func are of type T

template<typename T, typename Func>
struct count_of_type;

template<typename T>
struct count_of_type<T, void()>  static constexpr std::size_t value = 0; ;

template<typename T, typename FirstArg, typename...RestArgs>
struct count_of_type<T, void(FirstArg, RestArgs...)> 
  static constexpr std::size_t value = std::is_same<T, FirstArg>::value + count_of_type<T, void(RestArgs...)>::value;
;


// Define your structs

#define APPEND_SEMICOLON(FIELD) FIELD;

#define DEFINE_STRUCT(NAME, FIELDS, ...) \
  struct NAME  \
    int myInts[count_of_type<int, void(FIELDS, ##__VA_ARGS__)>::value]; \
    MAP(APPEND_SEMICOLON, FIELDS, ##__VA_ARGS__) \
  ;

DEFINE_STRUCT(A,
    int a,
    char b,
    char c,
    int d,
    char e)

static_assert(std::is_same<decltype(A().myInts), int[2]>::value, "");

【讨论】:

有趣的解决方案。我相信这为我的问题提供了解决方案,但这不是我可以用于我的用例的解决方案。在我的例子中,避免需要指定类型的出现次数是为了降低支持可数复杂类型的开发复杂性并使计数自动化。但是,在复杂类型更改之前或复杂类型更改时指定# of complex types 比包装整个结构所做的使结构更难维护/更难使用要好。无论如何,谢谢你,我认为这是我所设想的最好的!【参考方案2】:

某些类型可以使用magic_get library。限制是:

T 必须是 constexpr 聚合可初始化且不得包含引用或位域

您帖子中的结构A 满足此条件。

magic_get 使用聚合初始化检测非静态数据成员的数量。基本上,这个想法是,如果您有某种类型 U 可以转换为任何其他类型,那么当 U()s 的数量等于聚合 T 中的元素数量时,TU(), U(), ..., U() 将是格式良好的. (如果T 的某些成员具有默认成员初始化程序或可以进行值初始化,则当初始化程序少于元素时,此表达式也可能是格式正确的,因此您必须采用最大的工作数。)和SFINAE 可用于检测这样的表达式是否格式良好。

你可以在fields_count.hpp看到所有血淋淋的细节

【讨论】:

它需要完整的类,所以不能用于定义成员,只是为了检查它。 @Jarod42 好点。我没有仔细阅读

以上是关于编译时:计算类型 X 的成员的 #(~N) 个并定义一个成员数组 [N]?的主要内容,如果未能解决你的问题,请参考以下文章

编译类型向量类的私有成员时出错 - C++ [重复]

struct结构体内存大小

类成员的编译顺序之嵌套类型对类的影响

无法定义使用'dynamic'的类或成员,因为编译器需要输入'System.Runtime.CompilerServices.DynamicAttribute'类型(代

结构体变量的sizeof计算

如何强制类型在编译时实现特征?