C语言中如何实现函数重载?

2023-11-21

C语言中有没有办法实现函数重载?我正在寻找要重载的简单函数,例如

foo (int a)  
foo (char b)  
foo (float c , int d)

我认为没有直接的方法;我正在寻找解决方法(如果存在)。


Yes!

自从提出这个问题以来,标准 C(无扩展)已经有效地gained支持函数重载(不是运算符),这要归功于添加了_GenericC11 中的关键字。 (GCC 从 4.9 版本开始支持)

(重载并不是真正按照问题中所示的方式“内置”的,但是实现类似的功能非常容易。)

_Generic是与以下同族的编译时运算符sizeof and _Alignof。标准第 6.5.1.1 节对此进行了描述。它接受两个主要参数:一个表达式(在运行时不会计算)和一个类型/表达式关联列表,看起来有点像switch block. _Generic获取表达式的整体类型,然后“切换”它以选择列表中的最终结果表达式作为其类型:

_Generic(1, float: 2.0,
            char *: "2",
            int: 2,
            default: get_two_object());

上述表达式的计算结果为2- 控制表达式的类型是int,所以它选择与关联的表达式int作为值。这些在运行时都不会保留。 (这default子句是可选的:如果省略它并且类型不匹配,则会导致编译错误。)

这对于函数重载很有用,因为它可以由 C 预处理器插入,并根据传递给控制宏的参数类型选择结果表达式。所以(来自 C 标准的示例):

#define cbrt(X) _Generic((X),                \
                         long double: cbrtl, \
                         default: cbrt,      \
                         float: cbrtf        \
                         )(X)

该宏实现了一个重载cbrt操作,通过将参数类型分派给宏,选择适当的实现函数,然后将原始宏参数传递给该函数。

因此,要实现您的原始示例,我们可以这样做:

foo_int (int a)  
foo_char (char b)  
foo_float_int (float c , int d)

#define foo(_1, ...) _Generic((_1),                                  \
                              int: foo_int,                          \
                              char: foo_char,                        \
                              float: _Generic((FIRST(__VA_ARGS__,)), \
                                     int: foo_float_int))(_1, __VA_ARGS__)
#define FIRST(A, ...) A

在这种情况下,我们可以使用default:第三种情况的关联,但这并没有演示如何将原则扩展到多个参数。最终的结果是你可以使用foo(...)在您的代码中,无需担心(很多[1])其参数的类型。


EDIT Cosinus 对于多参数重载有一个更优雅的解决方案,可与 C23 或 GNU 扩展一起使用,下面的技术是针对 C11 编写的(它并不想让您这样做)。

对于更复杂的情况,例如函数重载大量参数或不同数量的参数,您可以使用实用程序宏自动生成静态调度结构:

void print_ii(int a, int b) { printf("int, int\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }

#define print(...) OVERLOAD(print, (__VA_ARGS__), \
    (print_ii, (int, int)), \
    (print_di, (double, int)), \
    (print_iii, (int, int, int)) \
)

#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)
#include "activate-overloads.h"

int main(void) {
    print(44, 47);   // prints "int, int"
    print(4.4, 47);  // prints "double, int"
    print(1, 2, 3);  // prints "int, int, int"
    print("");       // prints "unknown arguments"
}

(在这里实施)因此,通过一些努力,您可以减少样板文件的数量,使其看起来非常像本地支持重载的语言。

作为旁白,这已经是可能的过载numberC99 中的参数(不是类型)。


[1] 请注意,C 评估类型的方式可能会让您陷入困境。这会选择foo_int例如,如果您尝试向其传递字符文字,你需要搞乱一下如果您希望重载支持字符串文字。不过总体来说还是很酷的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言中如何实现函数重载? 的相关文章

随机推荐