對於「語言的代碼意識」,有沒有更好的我比Lisp和它的宏觀設施 - 特別是Common Lisp更加明顯。但是大多數情況下,在編譯時或宏擴展時,對象的類型是未知的。對於文字,這些類型是已知的,所以你可以找到侵略性宏的例子,它們測試一個對象是否是一個文字,如果是,就以一種方式處理它 - 也許根據它的類型 - 然後準備檢測到的變量用於運行時型檢測。
這是我幾年前從CLLIB庫(CLOCC庫的一部分)改編的一個示例。我們的目標是提供將前綴字符串從其他字符串中剔除並且匹配前綴的函數。前綴可能在宏擴展時已知,或者可能不是。如果是,我們可以進行優化:首先計算前綴的長度並將其嵌入爲文字,以便在每次調用生成的函數時不重新計算它。宏開始令人生畏,但實際生成的代碼很小。
(defmacro after-prefix-core (comparison-op prefix string &optional length)
"Similar to cllib:string-beg-with-cs."
(flet ((chop (prefix prefix-length string string-length)
`(when (and (>= ,string-length ,prefix-length)
(,comparison-op ,prefix ,string :end2 ,prefix-length))
(subseq ,string ,prefix-length ,string-length))))
(let* ((gstring (gensym "STRING-"))
(gstring-length (gensym "STRING-LENGTH-")))
`(let* ((,gstring ,string)
(,gstring-length ,(or length `(length ,gstring))))
,(if (stringp prefix)
;; Constant -- length known at expansion time.
(let ((prefix-length (length prefix)))
(chop prefix prefix-length gstring gstring-length))
;; Other form -- length not known at expansion time.
(let ((gprefix (gensym "PREFIX-"))
(gprefix-length (gensym "PREFIX-LENGTH-")))
`(let* ((,gprefix ,prefix)
(,gprefix-length (length ,gprefix)))
,(chop gprefix gprefix-length gstring gstring-length))))))))
(defmacro after-prefix (prefix string &optional length)
"Similar to cllib:string-beg-with."
`(after-prefix-core string-equal ,prefix ,string ,length))
(defmacro after-prefix-cs (prefix string &optional length)
"Similar to cllib:string-beg-with-cs."
`(after-prefix-core string= ,prefix ,string ,length))
見表格
(if (stringp prefix)
中間
?這是在宏展開時檢查第一個參數,並且根據參數是文字還是符號,其類型可能已知也可能不知道。如果類型是一個符號,我們假設,我們應該等到運行時重新考慮它作爲指向其他值的變量。
下面是形式(after-prefix foo bar)
膨脹:
(LET* ((#:STRING-5340 BAR) (#:STRING-LENGTH-5341 (LENGTH #:STRING-5340)))
(LET* ((#:PREFIX-5342 FOO) (#:PREFIX-LENGTH-5343 (LENGTH #:PREFIX-5342)))
(WHEN
(AND (>= #:STRING-LENGTH-5341 #:PREFIX-LENGTH-5343)
(STRING-EQUAL #:PREFIX-5342 #:STRING-5340 :END2 #:PREFIX-LENGTH-5343))
(SUBSEQ #:STRING-5340 #:PREFIX-LENGTH-5343 #:STRING-LENGTH-5341))))
注意,變量#:PREFIX-LENGTH-5343
被綁定到計算長度的FOO
,這裏結合到可變#:PREFIX-5342
。
現在看看擴張形式(after-prefix "foo" bar)
,現在在哪裏前綴是一個字符串文字:
(LET* ((#:STRING-5463 BAR) (#:STRING-LENGTH-5464 (LENGTH #:STRING-5463)))
(WHEN (AND (>= #:STRING-LENGTH-5464 3) (STRING-EQUAL "foo" #:STRING-5463 :END2 3))
(SUBSEQ #:STRING-5463 3 #:STRING-LENGTH-5464)))
現在有沒有計算的「富」的長度;它被內聯爲3.
在這個例子中看起來像是太多的工作,但能夠做這樣的事情是一個很好的能力,因爲你的問題被視爲。
如果'if'中的表達式可以在編譯時確定,許多C和C++編譯器將刪除未使用的代碼。不知道這是否完全回答你的問題。 – 2009-11-11 20:57:30
否 - 上面的例子不會編譯,因爲某些靜態代碼塊中的代碼無效。例如。如果T是int類型,則值.__ repr __()將是編譯錯誤。 – Grumdrig 2009-11-11 21:03:44
您需要爲上述內容編譯「靜態if(is(typeof(value .__ repr__)))」。或者「static if(__ traits(compiles,value .__ repr__))」。 – Baxissimo 2009-11-11 21:35:05