【问题标题】:What's the C strategy to "imitate" a C++ template ?“模仿” C++ 模板的 C 策略是什么?
【发布时间】:2011-03-03 02:03:51
【问题描述】:

在阅读了一些关于 stackoverflow 的示例并按照我之前的问题 (1) 的一些答案之后,我最终为此制定了一个“策略”。

我来了:

1).h 文件中有一个声明部分。在这里,我将定义数据结构和访问接口。例如:

/**
 * LIST DECLARATION. (DOUBLE LINKED LIST)
 */
#define NM_TEMPLATE_DECLARE_LIST(type) \
typedef struct nm_list_elem_##type##_s { \
    type data; \
    struct nm_list_elem_##type##_s *next; \
    struct nm_list_elem_##type##_s *prev; \
} nm_list_elem_##type ; \
typedef struct nm_list_##type##_s { \
    unsigned int size; \
    nm_list_elem_##type *head; \
    nm_list_elem_##type *tail; \
    int (*cmp)(const type e1, const type e2); \
} nm_list_##type ; \
\
nm_list_##type *nm_list_new_##type##_(int (*cmp)(const type e1, \
    const type e2)); \
\
(...other functions ...)

2)将接口中的函数封装在MACROS内部:

/**
 * LIST INTERFACE
 */
#define nm_list(type) \
    nm_list_##type

#define nm_list_elem(type) \
    nm_list_elem_##type

#define nm_list_new(type,cmp) \
    nm_list_new_##type##_(cmp)

#define nm_list_delete(type, list, dst) \
    nm_list_delete_##type##_(list, dst)

#define nm_list_ins_next(type,list, elem, data) \
    nm_list_ins_next_##type##_(list, elem, data)

(...others...)

3) 实现功能:

/**
 * LIST FUNCTION DEFINITIONS
 */
#define NM_TEMPLATE_DEFINE_LIST(type) \
nm_list_##type *nm_list_new_##type##_(int (*cmp)(const type e1, \
    const type e2)) \
{\
    nm_list_##type *list = NULL; \
    list = nm_alloc(sizeof(*list)); \
    list->size = 0; \
    list->head = NULL; \
    list->tail = NULL; \
    list->cmp = cmp; \
}\
void nm_list_delete_##type##_(nm_list_##type *list, \
    void (*destructor)(nm_list_elem_##type elem)) \
{ \
    type data; \
    while(nm_list_size(list)){ \
        data = nm_list_rem_##type(list, tail); \
        if(destructor){ \
            destructor(data); \
        } \
    } \
    nm_free(list); \
} \
(...others...)

为了使用这些结构,我必须创建两个文件(我们称它们为templates.ctemplates.h)。

templates.h 中,我必须使用NM_TEMPLATE_DECLARE_LIST(int)NM_TEMPLATE_DECLARE_LIST(double),而在templates.c 中,我需要使用NM_TEMPLATE_DEFINE_LIST(int)NM_TEMPLATE_DEFINE_LIST(double),以便获得整数、双精度和以此类推,生成。

通过遵循这个策略,我必须将所有“模板”声明保存在两个文件中,同时,我需要在需要数据结构时包含templates.h。这是一个非常“集中”的解决方案。

您是否知道在 C++ 中“模仿”(在某些时候)模板的其他策略?您是否知道改进此策略的方法,以便以更加分散的方式保持事物,这样我就不需要两个文件:templates.ctemplates.h

【问题讨论】:

  • 您可以在 C 之上实现一种支持模板的语言。;) 虽然我不知道我认为合适的替代方法,但几乎就是这样根据我的经验,每个人在确实需要模板时都会完成这种模式。
  • 我想使用 C++ 是不可能的?
  • 是的,C++ 是不可能的。
  • @jer:为什么要发明自己?只需使用Comeau C++。最符合标准的 C++ 编译器带有出色的错误消息并生成 C 代码。
  • 老实说,我认为构建一些代码生成器来为您生成数据结构可能更简单。您可以使用类型名称(或任何命名约定)为函数添加前缀。

标签: c++ c templates macros c-preprocessor


【解决方案1】:

我可能不应该承认这样做,但是当我过去在 C 语言中需要“模板化”容器时,我将“模板化队列类”编写为一对特殊文件,如下所示:

文件 MyQueue.include_h:

/** NOTE: THIS IS NOT a REAL .h FILE, it only looks like one!  Don't #include it! */
struct MyQueueClass
{
   void init_queue(MyQueueClass * q);
   void push_back(MyQueueClass * q, MyQueueClassItem * item);

   [....All the other standard queue header declarations would go here....]

   MyQueueClassItem * _head;
   MyQueueClassItem * _tail;
   int _size;
};

文件 MyQueue.include_c:

/** NOTE: THIS IS NOT A REAL .c FILE, it only looks like one! Don't compile directly! */
void init_queue(MyQueueClass * q)
{
   q->_size = 0;
   q->_head = q->_tail = NULL;
}

void push_back(MyQueueClass * q, MyQueueClassItem * item)
{
   if (q->_head == NULL) q->_head = q->_tail = item;
   else
   {
      q->_tail->_next = item;
      item->_prev = q->_tail;
      q->_tail = item;
   }
   q->_size++;
}

[....All the other standard queue function bodies would go here....]

然后,每当我想“实例化”我的队列“模板”以使用特定的项目类型时,我都会将这样的内容放入实际的 .c 和 .h 文件中:

在我的一个真实 .h 文件中:

#define MyQueueClass struct SomeSpecificQueueType
#define MyQueueClassItem struct SomeSpecificQueueTypeItem
# include "MyQueue.include_h"
#undef MyQueueClassItem
#undef MyQueueClass

在我的一个真实的 .c 文件中(不管是哪个):

#define MyQueueClass struct SomeSpecificQueueType
#define MyQueueClassItem struct SomeSpecificQueueTypeItem
# include "MyQueue.include_c"
#undef MyQueueClass
#undef MyQueueClassItem

....然后,C 预处理器就像一个穷人的模板扩展器,不需要整个“模板定义”由一个巨大的#define 语句组成。

【讨论】:

  • 它不允许在一个文件中声明两个包含不同类型值的队列 - 函数名称会发生​​冲突。
【解决方案2】:

您的示例只是模板的众多可能用途之一 - 生成通用数据结构。这个例子不需要任何使模板强大的推理;要求可以创建通用数据结构的东西与要求等效于 C++ 模板的东西并不是同一个问题。

<tgmath.h> 使用的一些实现技术可能会提供一些类型推断功能,但它们仍然比 C++ 模板更弱且可移植性较差。

对于容器的具体示例,我不会打扰 - 只需创建一个包含 void* 数据的列表,然后使用 malloc 和 free 来创建数据,或者给列表提供一对函数指针来创建并破坏价值观。您也可以只依靠客户端来管理数据,而不是将值作为列表的成员。如果要保存间接,请使用可变长度数组作为数据成员。由于 C 不像 C++ 那样类型安全,因此拥有 void* 数据不是问题。

您可以使用宏进行一些复杂的代码生成,但也有其他工具可以生成代码。就我个人而言,我喜欢使用 XSLT 来生成代码,但是在构建过程中你有一个完全非 C 类的部分。

【讨论】:

    【解决方案3】:

    省点麻烦,使用现有的queue(3) 宏集 - 久经考验,用于内核源代码等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-27
      • 1970-01-01
      • 2014-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多