【问题标题】:c\c++ - Functions with unions as arguments to meet specific requirementsc\c++ - 以联合作为参数以满足特定要求的函数
【发布时间】:2013-03-01 23:23:54
【问题描述】:

我正在为一个设备提供功能的工程库。该设备有一些共同的操作,但不同的算法来完成这些操作。我想要一个特定操作的函数原型,而不是一堆函数原型,而不是:

Alg1_Foo();
Alg2_Foo();
...

我想要这个:

Foo(alg);

但我不想将 alg 作为单独的参数传递,因为即使没有它,函数也会有很多参数,它们会有用于识别和/或授权设备的参数,输入参数,输出参数(至少其中之一),所以我认为将 alg 添加为单独的参数会很烦人。

所以我的想法是提供这样的解决方案:

Foo(const SomeUnion& some_union);

地点:

union SomeUnion {
  AlgId alg_id;
  alg1::SomeStruct alg1_some_struct;
  alg2::SomeStruct alg2_some_struct;

  SomeUnion(alg1::SomeStruct some_struct) { alg1_some_struct = some_struct; };
  SomeUnion(alg2::SomeStruct some_struct) { alg2_some_struct = some_struct; };
};

特定算法的结构会是这样的:

namespace alg1 {
  struct SomeStruct {
    static const AlgId alg_id = ALG1;
    . . .
  };
}

所以如果要执行 alg1,我们将适当的结构传递给 Foo,它可以在 C++ 中工作,比如说

alg1::SomeStruct a;
Foo(a);

但我希望我的库保持纯 C 的可能性。当然我需要:

  1. 删除引用并用指针替换它们;

  2. 删除命名空间(我们仍然可以在结构的帮助下模拟它们(此线程可能对感兴趣的人有所帮助:Namespaces in C);

  3. 将定义结构的 C++ 样式替换为 C 中的结构,并在标签命名空间中定义名称 (typedef struct tagStruct {...} Struct;);

  4. 从内部结构和联合中删除函数。

但是,虽然我不明白是否有可能通过维护 C 来完成我想做的事情......你看到了吗?或者将 alg_id 作为一个单独的参数传递而不打扰联合和结构是否更简单(但如果可能的话,我想避免它)?

【问题讨论】:

  • 那么你为什么不希望每个算法都有单独的函数呢?
  • 问题是什么?你想解决什么问题?
  • 我想到了过度设计。
  • 也许它是过度设计的,但我们有一个库,它是由在我之前在公司工作的人设计的,我们为每个单独的算法都有很多原型。我不会说维护它们很容易,比如说,如果特定操作的逻辑发生变化,我们需要更改与之相关的所有原型。这只是上面写的一个建议,如果不可能在 C 中完成,我会接受它并留下单独的函数或添加 alg_id 作为参数。但如果你有一些线索,他们将不胜感激。
  • 使用 C++,您可以重载 Foo 为每个算法采用不同的结构。所以你实际上是在定义一堆函数(你说你不想这样做,但没有给出任何理由),它们都具有相同的名称。

标签: c++ c arguments compatibility unions


【解决方案1】:

在我看来,这似乎是一个典型的案例,有人试图“以错误的方式”解决问题。

如果您对函数有“很多参数”,那么使用struct 就可以了。但是在struct 中隐藏“您实际调用的函数”,然后在union 中包含struct 的几个变体,现在我们正试图在一个函数中塞进太多东西。开始拆分函数,使其只需要一个 struct - 删除您的 union 作为参数 - 这是错误的。 [我曾使用过与此类似的代码——因为您将错误类型的 union 参数传递到函数中,因此可能会潜入一些执行错误的代码并导致一些难以发现的错误,这使得这确实是一个不好的解决方案]。如果您将错误类型的结构传递给普通函数,那么编译器会告诉您。如果您填写联合的错误部分,则使用结构“正确”部分的代码将获得“奇怪”数据[很可能是未定义的行为] - 这种类型的错误很难找到。

所以,是的,拆分你的功能,移除联合!

编辑: 如果您希望拥有一个简单且一致的接口,您想到的一个建议是您有一个工厂函数,您将alg_id 传递给它,它返回一个指向相关函数的函数指针。不幸的是,如果每个函数的接口是我建议的不同结构,那么您仍然有可能将数据结构和函数混淆,但它确实减少了“已​​发布函数”的数量 - 事实上,这些功能不需要在提供它们的模块[库甚至目标文件]之外完全可见。

【讨论】:

  • 感谢您的详细解答。我理解这样做的缺点......我的想法是:1)在添加新算法时可以不改变库的接口(保持函数名称相同)(所以只有结构会改变); 2) 防止用户在想要使用某些算法时使用错误的结构,所以我决定在每个结构中硬编码 alg_id。使用拆分功能可以轻松实现第 2 点,但第 1 点则不然。会有一些层调用库的功能,每次都改变它的接口不会那么容易。还是必要的程度?
  • 如果您正在更改算法,那么您可能会引入新的数据结构[如果我正确理解您的问题],这意味着新的头文件 - 因此同时引入新功能不应该是除非您遇到名称冲突,否则会出现问题。使用不太可能与客户端代码名称冲突的名称会有所帮助,例如使用前缀,然后记录“客户端函数不应以 PfX_ 或任何前缀开头。接口库无疑也需要更改以支持新算法。(更多...)
  • 将alg_id 放在struct 中没有帮助,除非您确定 1. 对于任何两个结构,alg_id 不在同一个位置。 2. 所使用的数据均不得与值alg_id 混淆。你添加的功能越多,这两者就越难实现。另请参阅上面的编辑...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
  • 2021-05-29
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多