我正在使用经典的C进行这个类赋值,并且我遇到了关于带有变量参数count和type的回调函数的问题。
基本上,我正在处理一个哈希树(一棵树,其中每个节点都是一个哈希树),我有一个特定的遍历策略,它将被多次用于不同的目的,所以我把它实现为{ {1}},因此被称为回调的函数将以任何必要的方式处理Element。
问题是,在我的问题中的大多数情况下,回调函数必须采用不同的参数。我知道如何使用'variadic'函数(使用stdarg,printf-way)设计带有变量参数列表的函数,但我不知道如何将这些参数“重新”回到回调函数。
让我提供一个具体的例子:假设我有一个名为ht_walk(HashTree tree, (*callback)(Element e))
的回调函数,而我的ht_walk声明现在是addToList(Element e, List list)
。考虑我想在下面的代码片段中使用ht_walk:
ht_walk(HashTree tree, (*callback)(Element e), ...)
有办法做到这一点吗?提前谢谢!
答案 0 :(得分:3)
您可以使用以下两种方法之一解决此问题。
最常见,最易理解,最简洁的方法是使用“用户”结构:
void ht_walk(HashTree tree, void (*callback)(Element e, void *user), void *user);
void addToList(Element e, void *arg)
{
STATIC_ASSERT(sizeof(void *) >= sizeof(List));
List list = arg;
/* ... */
}
HashTree my_tree = ht_create();
/* run some algorithm that populates the tree somehow */
List my_list = list_create();
ht_walk(my_tree, addToList, my_list);
另一种方法是接受va_list
:
#include <stdarg.h>
void ht_walk(HashTree tree, void (*callback)(Element e, va_list args), ...)
{
for(..)
{
va_list args;
va_start(args, callback);
callback(element, args);
va_end(args);
}
}
void addToList(Element e, va_list args)
{
List list = va_arg(args, List);
/* ... */
}
HashTree my_tree = ht_create();
/* run some algorithm that populates the tree somehow */
List my_list = list_create();
ht_walk(my_tree, addToList, my_list);
答案 1 :(得分:1)
有一系列用于处理可变参数的函数和宏(例如,va_start) GNU有一个good guide here
话虽如此,你似乎在描述一种访客模式。我不确定我喜欢在这里使用可变参数列表。如果你通常不能确定你的回调将为所有节点一致地获得什么参数,那么你就很难开始。
答案 2 :(得分:1)
我不认为你想要做的是传递任意数量的参数。我认为你在这里有一种情况,你有多种类型的回调。在你的例子中,你传递了一个List,但是你有时也提到你会传递一个Element。所以在我看来你真正想做的是声明你的回调取一个void *和一个标志来表明它是什么。类似的东西:
void callback(void* arg, int type) {
switch (type) {
case ARG_TYPE_LIST:
List* list = (List*)arg;
...
break;
case ARG_TYPE_ELEMENT:
Element* ele = (Element*)arg;
...
break;
...
}
如果您将事物作为列表传递,列表应该知道计数,因此您不必担心传递它。
或者,您可以定义多种类型的回调,并始终根据您需要执行的处理类型回调正确的回调。
如果您没有被限制为直接C(即您可以使用C ++),您可以使用boost::bind进行调查,因为它对此类事情非常有用。
答案 3 :(得分:0)
我相信您使用va_list
宏。请参阅the man page for stdarg。
我试过这个已经有一段时间了......
答案 4 :(得分:0)
我会传入一个void *,因为我认为你不能在回调函数中使用可变数量的参数。我可能错了。
typedef void (*tree_walk_callback)(Element e, void *data);
add_element(Element e, void *data)
{
List *list = (List *)data;
add_element_to_list(list, e);
}
...in your function...
List my_list;
ht_walk(my_tree, &add_element, (void *)&my_list);
如果用户想要传递多个参数,那么他们会传递一个包含所需内容的结构。