2010-06-12 71 views
2

閱讀計算器的一些例子,以下爲一些我以前的問題的答案(1)後,我最終得出了「戰略」這個。「模仿」C++模板的C策略是什麼?

我已經來到這個:

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)裹中相應的界面中宏功能:

/** 
* 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

+1

你可以實現一種支持C語言模板的語言; 雖然我不知道另一種方法,但我認爲合適,但幾乎每個人都可以完成這一任務模式,當他們確實需要模板時,從我的經驗。 – jer 2010-06-12 21:08:21

+0

我想使用C++將是不可能的? – 2010-06-12 21:21:36

+0

是的,C++是不可能的。 – 2010-06-12 21:22:47

回答

1

你舉的例子只是模板的許多可能的用途之一 - 生成一個通用的數據結構。這個例子不需要任何使模板強大的推理;要求一些可以讓你創建通用數據結構的東西並不是要求相當於C++模板的東西。

一些用於<tgmath.h>可能會給一些類型推理能力實現技術,但他們仍然是弱得多,比C++模板的移植性較差。

對於容器的具體示例,我不打擾 - 只需在其中創建一個帶有void *數據的列表,並使用malloc和free來創建數據,或者讓列表有一對函數指針創造和摧毀價值。您也可以僅依靠客戶端來管理數據,而不是將該值作爲列表的成員。如果要保存間接尋址,請使用可變長度數組作爲數據成員。由於C不像C++那樣類型安全,因此擁有void *數據不是問題。

你可以做一些複雜的代碼生成與宏,但也有其他工具來生成代碼。就我個人而言,我喜歡使用XSLT進行代碼生成,但是您的構建過程完全沒有類似C的部分。

1

保存自己的一些麻煩和利用現有queue(3)組宏 - 久經考驗,在內核源代碼中使用等

2

我可能不應該承認這樣做,但是當我需要的「模板化」在過去丙地的容器,我寫的「模板化的隊列班」爲一對特殊的文件,如:

文件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....] 

然後,每當我想 「實例」 我的隊列 「模板」 使用一個特定的項目,典型值E,我把這樣的事情爲實際的.c和.h文件:

在我真正的.h文件之一:

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

在我真正的.c文件一個(它不「T無論哪一個):

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

....和急,C預處理器作爲一個窮人的模板擴展,而無需完整的‘模板定義’被開出了巨大的#define的聲明。

+2

它不允許在一個文件中聲明兩個持有不同類型值的隊列 - 函數名稱會衝突。 – 2010-06-12 23:43:48