c++函数,它在不使用模板的情况下接受任何数据类型

c++ function that takes any data type without using templates?

本文关键字:情况下 数据类型 任何 函数 c++      更新时间:2023-10-16

我有一个赋值,它要求为任何数据类型编写一个函数。该函数应该打印结构的字节,识别数据结构使用的字节总数,并区分用于成员的字节和用于填充的字节。

我的第一反应,和大多数类的反应一样,就是使用模板。这允许您编写一次函数,并收集传递到函数中的对象的运行时类型。使用memset和typeid可以很容易地完成所要求的内容。然而,我们的教授刚刚看到了我们关于模板和该死的模板的讨论。

看到这件事后,我陷入了困境,我正在寻找一点指导,作为绕过这件事的最佳方式。我研究过的一些事情:

  • 带有显式类型转换的void指针(这看起来会很混乱)
  • 基类只有虚拟函数,所有数据结构都从中继承,这样做似乎有点奇怪
  • 与我们的每个数据结构都有"友谊"的基类
  • 为问题集中的每个数据结构重写一个函数(我认为这是最糟糕的解决方案)

希望我忽略了一个常见的c++工具,有人有什么想法吗?

尽可能愚蠢地对待函数,事实上,把它当作什么都不知道,所有信息都必须传递给它。

功能参数:

  • 结构地址,作为uint8_t *。(需要打印字节)
  • 结构大小,以字节为单位。(需要打印字节并打印总尺寸)
  • 成员信息的向量:成员长度或成员使用的字节数之和

需要向量来满足打印成员使用的字节和填充使用的字节的要求。您可以选择传递成员的总和。

示例:

  void Analyze_Structure(uint8_t const *  p_structure,
                         size_t           size_of_structure,
                         size_t           size_occupied_by_members);

这个赋值的技巧是找出如何让调用函数确定这些项。

希望这能有所帮助。

编辑1:

struct Apple
{
  char    a;
  int     weight;
  double  protein_per_gram;
};
int main(void)
{
  Apple granny_smith;
  Analyze_Structure((uint8_t *) &granny_smith,
                    sizeof(Apple),
                    sizeof(granny_smith.a)
                    + sizeof(granny_smith.weight)
                    + sizeof(granny_smith.protein_per_gram);
  return 0;
}

我有一个任务,要求为任何数据类型编写一个函数。

这意味着要么是模板(你的教授驳回了),要么是void*,要么是可变数量的参数(类似于printf)。

该功能应该打印结构的字节

void your_function(void* data, std::size_t size)
{
    std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(data);
    for(auto x = bytes; x != bytes + size; ++x)
        std::clog << "0x" << std::hex << static_cast<std::uint32_t>(*x) << " ";
}

[…],并标识数据结构使用的字节总数,同时区分用于成员的字节和用于填充的字节。

在这一点上,我迷失了方向:用于填充的字节(根据定义)不是结构的一部分。考虑:

struct x { char c; char d; char e; }; // sizeof(x) == 3;
x instance{ 0, 0, 0 };
your_function(&instance, sizeof(x)); // passes 3, not 4 (4 for 32bits architecture)

理论上,您也可以将alignof(instance)传递给函数,但这不会告诉您内存中字段的对齐方式(据我所知,它还没有标准化,但我可能错了)。

这里有几种可能性:

  1. 你的教授学会了";"黑客";C++,在10或20年前被认为是好代码,但没有更新他的知识(C风格的代码、指针、直接内存访问和"智能黑客"都在这里)。

  2. 他不知道如何准确地表达自己想要的东西,也不知道使用什么术语("为任何数据类型编写函数"太模糊了:作为一名开发人员,如果我得到了这项任务,首先要做的就是询问细节,比如"如何使用它?"answers"期望的函数签名是什么")。

    例如,这可以通过宏在一定程度上实现,但如果他希望你用宏代替函数和模板,你可能应该考虑更换教授。

  3. 他的意思是,你应该编写一些任意的数据类型(比如我上面的struct x),并围绕它定义你的API(不太可能)。

我不确定这样的函数是否可以在没有最少内省的情况下构建:你需要知道结构成员是什么,否则你只能访问结构的大小。

不管怎样,这是我的建议,只要代码的用户"合作",就可以在不进行内省的情况下工作。

函数将使用void*和size_t作为结构的地址和sizeof的参数。

0)允许用户创建所需类型的结构。

1) 让用户调用一个将所有字节设置为0的函数。

2) 让用户为结构的每个字段分配一个值。

3) 让用户调用您的一个函数,该函数会记录仍为0的每个字节。

4) 让用户调用一个将所有字节设置为1的函数。

5) 让用户再次为结构的每个字段分配一个值。(与第一次相同的值!)

6) 让用户调用您的函数,并计算之前标记为1 and的字节。这些是填充字节。

尝试先使用值0,然后使用值1的原因是用户分配的值可能包括字节0;但它们不能同时是字节0和字节1,因此其中一个测试将排除它们。

struct _S { int I; char C } S;
Fill0(S, sizeof(S));
// User cooperation
S.I= 0;
S.C= '';
Mark0(S, sizeof(S)); // Has some form of static storage
Fill1(S, sizeof(S));
// User cooperation
S.I= 0;
S.C= '';
DetectPadding(S, sizeof(S));

您可以将所有这些打包到一个函数中,该函数采用回调函数参数来执行成员分配。

void Assign(void* pS) // User-written callback
{
  struct _S& S= *(struct _S)pS;
  S.I= 0;
  S.C= '';
}