C中采用未知类型参数的泛型函数

Rém*_*ado 5 c generic-programming

我正在尝试使用未知类型参数创建一些函数来通用地应用函数。

让我们以一个可以应用于close(int fd)数组的每个元素的函数为例:

void for_each(void *array[], void (*func)(void *))
{
    for (size_t i = 0; array[i] != NULL; ++i)
        func(array[i]);
}
Run Code Online (Sandbox Code Playgroud)

如果我想将这个函数与 一起使用close(int fd),我必须制作一个这样的包装函数:

void close_fd(void *fd)
{
    close(*(int *)fd);
}
Run Code Online (Sandbox Code Playgroud)

我想将此for_each函数与字符串、浮点数和其他所有内容一起使用。

  • 如果没有包装部分,就没有什么可以实现的吗?
  • 我知道 C++ 有很多方法可以做到这一点,例如 lambdas、模板等,但是在 C 中有什么好方法吗?妥协

Lui*_*ado 1

嗯,很明显,您想针对不同的数据多次调用一个函数(同一函数)。但这些数据是在数组中传递的,根据定义,数组是相同类型的多个数据项的存储。所以最后没有特殊的构造可以做到这一点,只需用普通的 C 语言即可:

typedef .... MY_TYPE;

/* define a pointer to represent the type of callback pointer you are using */
typedef void (*callback_ptr)(MY_TYPE param);

/* this is the real callback function you are going to use */
void my_func1(MY_TYPE param){
    /* process a single MY_TYPE */
}

void my_funcN(MY_TYPE param) {
    /* another process function */
}

/* function to apply the callback to an array of MY_TYPE */
void for_each( MY_TYPE array[], size_t array_sz, callback_ptr f )
{
    int i;
    for (i = 0; i < array_sz; i++)
        f(array[i]);
}

....
MY_TYPE my_array[100] = { ... };
size_t my_array_sz = sizeof my_array / sizeof my_array[0];

for_each(my_array, my_array_sz, my_func1); /* process all by my_func1 */
for_each(my_array, my_array_sz, my_funcN); /* process all by my_funcN */
Run Code Online (Sandbox Code Playgroud)

void *非绝对必要时尽量避免使用。可能在早期设计阶段,您不知道它将要处理的实际数据类型,但是很明显,一旦编写了实际的调用语句,您就必须输入参数并使用返回值,所以您坚持然后到实际类型....这为您提供了有关如何声明回调指针和流程函数所需的提示。将实际类型放入函数调用中可以使编译器检查正确性,这有助于避免犯错误。

通用函数

C 中不支持泛型函数,但是如果您想要某种安排,允许您编写某些数据类型是泛型的函数,您可以使用宏来模拟它(您必须非常仔细地编写宏才能工作,但是可以获得非常好的近似值)

您可以使用宏为每种类型定义不同的函数cpp,如下所示:

func_def.h

#define FUNC(TYPE)                        \
        void my_func_##TYPE( TYPE param ) \
        {                                 \
          /* body of function */          \
        }
Run Code Online (Sandbox Code Playgroud)

然后在文件范围内包含以下函数:

程序.c

FUNC(int)
FUNC(double)
Run Code Online (Sandbox Code Playgroud)

这将扩展到:

        void my_func_int( int param )     \
        {                                 \
          /* body of function */          \
        }
    
        void my_func_double( double param ) \
        {                                   \
            /* body of function */          \
        }
Run Code Online (Sandbox Code Playgroud)

无论如何,您都会对参数进行类型检查。如您所见,您必须在函数名称中使用类型,因为 C 不支持函数重载(具有相同名称和不同参数列表的函数)。在这种情况下,回调my_func_*for_each_*函数都必须是定义,至于编译器完全进行类型检查。