2013-02-06 62 views
2

作爲問題的一個例子,有沒有什麼辦法可以在下面的代碼中實現宏partialconcatC預處理器中是否有部分宏應用程序/ currying可能?

#define apply(f, x) f(x) 

apply(partialconcat(he),llo) //should produce hello 

編輯:

這裏是另外一個例子,給定一個FOR_EACH可變參數宏(請見this answer另一個問題示例實現)。

假設我想在多個對象上調用成員, 可能在另一個宏中用於更大的目的。 我想,其行爲像這樣的宏callMember:

FOR_EACH(callMember(someMemberFunction), a, b, c); 

產生

a.someMemberFunction(); b.someMemberFunction(); c.someMemberFunction(); 

這需要callMember(someMember)以產生表現一個宏像

#define callMember_someMember(o) o.someMember() 

回答

1

C預處理器是隻有」 '一個簡單的文本處理器。特別是,一個宏不能定義另一個宏;您不能在宏的擴展中創建#define

我認爲,這意味着你的問題的最後兩行:

這需要callMember(someMember)生產行爲類似

#define callMember_someMember(o) o.someMember()

宏都無法實現與單C預處理器的應用程序(並且,在一般情況下,根據宏的定義,您需要預處理器應用任意次數)。

+0

正如我擔心。好,謝謝。 – Dylan

4

可以達到預期的結果使用的Vesa Karvonen的令人難以置信的「訂單式」語言/庫預處理:http://rosettacode.org/wiki/Order

這是通過對預處理器本身的頂部實現整個第二次高級別語言,支持諸如咖喱和一流的宏等等。雖然這非常重要,但非平凡的Order代碼需要很長時間才能編譯,因爲CPP並不是用於這種方式的,並且大多數C編譯器都無法處理它。它也非常脆弱:輸入代碼中的錯誤往往會產生難以理解的亂碼輸出。

但是,它可以完成,並在一個預處理程序中完成。這只是一個很多比你可能期待的更復雜。

+0

非常感謝您的鏈接。訂單令人着迷。我正在考慮修改我的工具鏈,以便在所有平臺上使用符合C99的預處理器(例如,使用VC++的Windows上的Boost Wave)來使用它(並處理其他惱人的VC++預處理器錯誤/不合規)。 – Dylan

1

使用高階宏:

#define OBJECT_LIST(V) \ 
    V(a) \ 
    V(b) \ 
    V(c) 

#define MEMBER_CALL(X) \ 
    X.some_func(); 


OBJECT_LIST(MEMBER_CALL) 

輸出

$ g++ -E main.cc 
# 1 "main.cc" 
# 1 "<command-line>" 
# 1 "/usr/include/stdc-predef.h" 1 3 4 
# 1 "<command-line>" 2 
# 1 "main.cc" 
# 10 "main.cc" 
a.some_func(); b.some_func(); c.some_func(); 

,因爲它是一個編譯時間循環,柯里化是困難的。OBJECT_LIST宏定義了此列表中每個用戶允許多少個參數進行咖喱。 (默認)函數調用參數是定義的一部分。您可以自由選擇不使用默認提供的參數或自己使用常量值。我無法找到一種合適的方法來減少預處理器中的參數數量。這個事實限制了這種技術的普遍性。

#define OBJECT_LIST(V) \ 
    V(a, 1,2,3) \ 
    V(b, 4,5,6) 

#define MEMBER_CALL(X, A1, A2, A3) \ 
    X.somefunc(A1, A2, A3); 

#define CURRY_CALL(X, A1, A2, A3) \ 
    X.somefunc(A1, 2, 2); 

#define NO_CURRY_CALL(X, A1, A2, A3) \ 
    X.xomefunc(A1); 


OBJECT_LIST(MEMBER_CALL) 
OBJECT_LIST(CURRY_CALL) 
OBJECT_LIST(NO_CURRY_CALL) 

輸出:

# 1 "main2.cc" 
# 1 "<command-line>" 
# 1 "/usr/include/stdc-predef.h" 1 3 4 
# 1 "<command-line>" 2 
# 1 "main2.cc" 
# 12 "main2.cc" 
a.somefunc(1, 2, 3); b.somefunc(4, 5, 6); 
a.somefunc(1, 2, 2); b.somefunc(4, 2, 2); 
a.somefunc(1); b.somefunc(4);