对于“语言的代码意识”,有没有更好的我比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