我现在正在C中做我的hw,我们在讲座中给出了以下代码来创建泛型类型。在C ++中,我知道你可以通过使用模板来实现这一点。我们的导师希望我们使用这些(所以现在我没有想到没有空虚*)。 但是,我对如何宣布这一点感到困惑。
typedef struct Cell(x) *List(x);
struct Cell(x) {
x* data;
List(x) next;
};
所以,我知道编译器看到的时候 列表(x) 它会在struct Cell(x)中替换,所以我尝试做List(int)a;在main()中,但是没有工作
答案 0 :(得分:3)
新版本的C添加了“类型通用表达式”,允许例如abs
函数使用不同的参数类型执行不同的操作。
但据我所知,仍然没有通用类型。您对实现集合类型的选择:
void*
我怀疑你打算做#3。有点像:
#define Cell(x) specialized_##x##_Cell
#define List(x) specialized_##x##_List
#define SINGLY_LINKED_LIST(x) \\
typedef struct Cell(x) *List(x); \\
struct Cell(x) \\
{ \\
x* data; \\
List(x) next; \\
};
然后你可以像
一样使用它SINGLY_LINKED_LIST(int)
int main(void)
{
List(int) a;
}
答案 1 :(得分:0)
有一种方法可以伪造C等带有宏的容器等模板。您必须编写两个生成声明的宏,以及新结构类型的定义以及作用于此类型的函数。
例如,对于(不完整的)列表类型:
#define DECLARE_LIST(T_Name, T_Tag, T_Type) \
\
typedef struct T_Name##Node T_Name##Node; \
typedef struct T_Name T_Name; \
\
struct T_Name { \
T_Name##Node *head; \
T_Name##Node *tail; \
int count; \
}; \
\
struct T_Name##Node { \
T_Type value; \
T_Name##Node *next; \
}; \
\
int T_Tag##_init(T_Name *ll); \
int T_Tag##_free(T_Name *ll); \
int T_Tag##_add(T_Name *ll, T_Type x);
#define DEFINE_LIST(T_Name, T_Tag, T_Type) \
\
int T_Tag##_init(T_Name *ll) \
{ \
ll->head = ll->tail = NULL; \
ll->count = 0; \
return 0; \
} \
\
int T_Tag##_free(T_Name *ll) \
{ \
while (ll->head) { \
T_Name##Node *next = ll->head->next; \
free(ll->head); \
ll->head = next; \
} \
return 0; \
} \
\
int T_Tag##_add(T_Name *ll, T_Type x) \
{ \
T_Name##Node *nd = malloc(sizeof(*nd)); \
\
if (nd == NULL) return -1; \
nd->next = NULL; \
nd->value = x; \
\
if (ll->head == NULL) { \
ll->head = ll->tail = nd; \
} else { \
ll->tail->next = nd; \
ll->tail = nd; \
} \
ll->count++; \
\
return 0; \
}
#define IMPLEMENT_LIST(T_Name, T_Tag, T_Type) \
DECLARE_LIST(T_Name, T_Tag, T_Type) \
DEFINE_LIST(T_Name, T_Tag, T_Type) \
如果要声明新的列表类型,则应在标头中DECLARE_LIST
和C源中的DEFINE_LIST
。如果类型是编译模块的私有类型,则可以将IMPLEMENT_LIST
放在C源代码中。
(宏是不完整的,因为它只为该类型实现了三个函数,这些函数本身没用。这只是为了显示基本的工作原理。你通常会得到两个巨大的宏。)
您可以像这样使用宏:
IMPLEMENT_LIST(Intlist, il, int)
IMPLEMENT_LIST(Stringlist, sl, char *)
这会创建两个新的列表类型Intlist
和Stringlist
,以及相应的函数,前缀为il_
和sl_
,您可以像其他函数一样使用它们:< / p>
int main()
{
Intlist il;
Stringlist sl;
il_init(&il);
sl_init(&sl);
il_add(&il, 1);
il_add(&il, 2);
il_add(&il, 5);
sl_add(&sl, "Hello");
sl_add(&sl, "World");
// ... more stuff ...
il_free(&il);
sl_free(&sl);
return 0;
}
此方法是类型安全的:例如,您无法将Stringlist
传递给il
函数。因为代码只包含宏,所以可以在头文件中实现它。
但是有一些限制:
作业是=
。这意味着例如字符串列表不能将副本保存在char数组中。如果客户端代码复制数据,则清理代码不知道它。您可以通过将复制,比较,构造函数和析构函数(也可以是宏)指定为宏参数来满足此类情况,但这很快就会变得复杂。
有“秘密”类型名称涉及上例中的节点类型。它们必须是有效的标识符(而不是C ++,编译器会创建mangles名称),这可能会导致令人惊讶的名称冲突。
使用私有实现时,函数不应该是static
。
它的优势在于,Stringlist
的名称比std::list<std::string>
更好。