를, 더 좋은 I가 없습니다 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)
를 참조하십시오? 이것은 매크로 확장 시간에 첫 번째 인수를 검사하고 인수가 리터럴인지 기호인지 여부에 따라 유형을 알 수도 있고 아닐 수도 있습니다.형식이 기호 인 경우 은 실행 시간까지 다른 값을 가리키는 변수로 다시 고려해야 할 때까지 기다려야하는으로 가정합니다. 가변 #:PREFIX-LENGTH-5343
가변 #:PREFIX-5342
여기 결합FOO
의 계산 된 길이에 결합되어
(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))))
참고
여기 (after-prefix foo bar)
형태에 대한 확장이다.
지금 접두사가 지금 리터럴 문자열 형태 (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)))
이제 더 컴퓨팅 "foo는"길이 없다; 그것은 3으로 인라 인됩니다.
이 예제에서는 너무 많은 작업처럼 보일 수 있지만 그런 것들을 할 수있는 것은 좋은 질문입니다.
많은 C 및 C++ 컴파일러는 'if'의 표현식이 컴파일 타임에 결정될 수 있다면 사용되지 않는 코드를 제거합니다. 이 질문에 완전히 대답해도 확실하지 않습니다. –
아니요 - 정적 if의 일부 블록에있는 코드가 유효하지 않기 때문에 위의 예는 컴파일되지 않습니다. 예 : T가 int 유형이면 값 .__ repr __()은 컴파일 오류입니다. – Grumdrig
위의 컴파일을 위해 "정적 if (type if (value .__ repr__))")를 작성해야합니다. 또는 "정적 if (__ traits (compiles, value .__ repr__))"). – Baxissimo