- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我想编写几个仅参数类型不同的函数。我知道 C++ 有 template
来很好地处理这个问题(虽然还不是很好,很少有编译器支持 export
关键字,并且查询此关键字以提高效率)。举个简单的例子,我想要:
template <typename T>
T add(T a, T b){
return a+b;
}
但是,在纯C中(有时我不得不选择纯C,因为某些平台没有C++编译器),不同版本必须有不同的函数名称,如
double addDouble(double a, double b){
return a+b;
}
int addInt(int a, int b){
return a+b;
}
嗯,当有两个版本时,我似乎可以在源文件中进行复制和粘贴工作;但是,在实践中,函数中会有很多行,而不仅仅是一个 return
语句,并且会有更多版本。 那么,我的问题是,如何优雅地实现不同类型版本的一系列功能?
到目前为止,我已经尝试了以下一些解决方案,但我认为它们远非理想。我需要您的建议,谢谢!
解决方案一:
#define mytype int
mytype addInt(mytype a, mytype b){
return a+b;
}
#undef mytype
#define mytype float
mytype addFloat(mytype a, mytype b){
return a+b;
}
#undef mytype
方案一的缺点:重复内容太多,如果要修改功能,必须修改所有版本。
解决方案 2:
func.h
#ifndef FUNC_H
#define FUNC_H
#define add(a, b, typename) functionAdd##typename(a,b)
/* function declarations */
#define declared(typename) \
typename functionAdd##typename(typename, typename)
declared(int);
declared(float);
#endif
func.c
#include "func.h"
/* function code */
#define functionAdd(a, b, typename) \
typename functionAdd##typename(typename a, typename b){ \
return a+b; \
}
/* function bodies (definitions) */
functionAdd(a, b, int)
functionAdd(a, b, float)
main.c
#include <stdio.h>
#include "func.h"
int main()
{
int x1 = add(1, 2, int);
float x2 = add(3.0, 4.0, float);
printf("%d %f\n", x1, x2);
return 0;
}
方案二的不足之处:因为函数是在define
中写的,调试起来比较困难。此外,\
符号很烦人。虽然,添加新版本很方便,只需将 declared(double)
插入 func.h 并将 functionAdd(a, b, double)
插入 func.c 即可实现此目的瞄准。
最佳答案
在许多(如果不是大多数)情况下,在 C 中模拟 C++ 模板的最佳方法是解决方案 3:参数化头文件和参数化实现文件。在您的情况下,它将按如下方式工作
创建一个元头文件,我们将其命名为 add.dec
,如下所示
TYPE_ CONCAT(add, SUFFIX_)(TYPE_ a, TYPE_ b);
TYPE_ CONCAT(sub, SUFFIX_)(TYPE_ a, TYPE_ b);
创建一个元实现文件,我们将其命名为add.def
,如下所示
TYPE_ CONCAT(add, SUFFIX_)(TYPE_ a, TYPE_ b){
return a + b;
}
TYPE_ CONCAT(sub, SUFFIX_)(TYPE_ a, TYPE_ b){
return a - b;
}
这两个文件由两个宏参数化:TYPE_
和SUFFIX_
,而CONCAT
是宏连接的传统实现
#define CONCAT_(a, b) a##b
#define CONCAT(a, b) CONCAT_(a, b)
现在,假设您想为 int
和 double
类型实例化您的"template"函数。在“真正的”头文件 add.h
中,您只需做
#define TYPE_ int
#define SUFFIX_ Int
#include "add.dec"
#undef TYPE_
#undef SUFFIX_
#define TYPE_ double
#define SUFFIX_ Double
#include "add.dec"
#undef TYPE_
#undef SUFFIX_
在一个“真正的”实现文件add.c
中
#define TYPE_ int
#define SUFFIX_ Int
#include "add.def"
#undef TYPE_
#undef SUFFIX_
#define TYPE_ double
#define SUFFIX_ Double
#include "add.def"
#undef TYPE_
#undef SUFFIX_
就是这样。通过这样做,您实例化了(声明和定义)addInt
、addDouble
、subInt
和 subDouble
。
当然,您可以对声明进行更多参数化。如果需要,您可以添加一个 DECLSPEC_
参数,以便能够将您的太阳函数声明为 static
。您可以为参数和返回值指定不同的类型(例如,ARG_TYPE_
和 RET_TYPE_
)。你可以参数化很多其他的东西。基本上,您可以参数化的内容没有限制。通过一些相当简单的宏技术,您甚至可以参数化函数期望的参数数量。
这实际上类似于您的解决方案 1 和解决方案 2 的组合。这基本上充分利用了您的两种方法。我想说这是模拟 C++ 模板实例化行为的最忠实尝试。
请注意,每个函数的主体仅显式键入一次(与您的解决方案 1 中的多个显式副本相反)。实际的函数体也很容易编辑,因为不必担心每行末尾那些讨厌的 \
(就像解决方案 2 中的情况一样)。
这种方法还有另一个有趣的好处:add.def
中的代码将保持“可调试”,即普通的交互式调试器通常能够进入这些实现(这在您的解决方案中是不可能的2).
关于c - 如何用纯C优雅地实现不同类型版本的一系列功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7186103/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!