문제

나는 D를 생각한다 static if 흥미로운 언어 기능입니다. 그것은 내 질문을 제기합니다. 컴파일러가 코드에 대한 강력한 개념을 가지고 있고 이들에 액세스 할 수있는 언어 시설이있는 컴파일링 된 언어의 다른 예가 있습니까?

예를 들어,이 코드는 비슷한 것을 제공합니다 repr 파이썬에서 :

char[] repr(T)(T value) {
  static if (is(typeof(value.__repr__))) { // class T provides a "repr()" method
    return value.__repr__();  
  } else static if (is(T:string)) {
    return `"` ~ value ~ `"`;
  // ...other cases...
  } else {
    return toString(value);
  }
}

나는 이것이 시원하다고 생각합니다. 왜냐하면 그것은 과부하가하는 일에 대한 다르고 일반적인 접근 방식을 허용하기 때문입니다. 이는 이와 같은 기능에 비해 코드를보다 역동적으로 만들 수있는 내부 방법입니다. 예를 들어, 컴파일러는 클래스의 필드 수를 알고 있지만 코드가 대부분의 언어로 컴파일 시간에 해당 정보에 액세스 할 수있는 방법은 없습니다.

경고 : 마지막 단락에는 의견이 있었지만, 나는 단지 논란을 불러 일으키지 않고 내 질문에 대한 동기와 설명을 제공한다는 의미입니다. 다른 편집 된 언어에 그러한 기능이 있는지 알고 싶습니다.

도움이 되었습니까?

해결책

실제 매크로가있는 모든 언어에는 정적 if의 형태가 있습니다. 예를 들어 LISP 및 네머리 매크로가 'if'및 for-loops와 같은 프로그래밍 구조를 사용하여 확장하는 코드를 구성 할 수 있습니다. 그것들은 본질적으로 시간을 정리하고 정적 if와 비슷한 일을 할 수 있습니다. Nemerle 매크로의 경우 기본적으로 컴파일 타임에 실행되는 컴파일러에 대한 플러그인입니다.

C ++에는 있습니다 MPL 부스트 a 정적 if의 종류 두 가지 유형 중에서 선택하는 데 사용할 수 있습니다. Run () 멤버에 두 가지 유형 안에 코드를 넣고 비슷한 것을 얻을 수 있지만 매우 번거로운 구문을 얻을 수 있습니다.

예를 들어 Boost MPL을 사용하면 다음과 같이 할 수 있습니다.

struct float_impl { 
    static void run() { /* float case code */ }
}
struct int_impl { 
    static void run() { /* int case code */ }
}

typedef typename if_<
          is_same<T, float>
        , float_impl
        , int_impl
        >::type impl_t;
impl_t::run();

D에서는 다음과 같습니다.

static if(is(T == float)) {
     /* float code */
}
else {
     /* int code */
}

다른 팁

"언어의 코드 인식"의 경우 LISP와 매크로 시설, 특히 일반적인 LISP보다 더 나은 것은 없습니다. 그러나 거래는 대부분의 시간에 물체의 유형이 컴파일 타임이나 거시 팬션 시간에 알려지지 않았다는 것입니다. 리터럴의 경우 유형이 알려져 있으므로 객체가 문자 그럴인지 확인하고, 그렇다면 유형을 기준으로 한 가지 방법을 처리하고 그렇지 않으면 감지 된 변수를 준비하는 공격적인 매크로의 예를 찾을 수 있습니다. 런타임 유형 검사를 위해.

다음은 내가 적응 한 예입니다 cllib 도서관 (의 일부 복막 도서관) 몇 년 전. 목표는 일치하는 접두사로 다른 문자열의 접두사 문자열을 자르는 기능을 제공하는 것입니다. 접두사는 거시적 확률 시간에 알려져 있거나 그렇지 않을 수도 있습니다. 그것이 최적화 할 수 있다면, 우리는 접두사의 길이를 먼저 계산하여 문자 그대로 포함시켜 생성 된 함수에 대한 각 호출마다 재 계산되지 않도록하십시오. 매크로는 처음에는 어려운 일이지만 실제 생성 된 코드는 작습니다.

(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)))

이제 "foo"의 길이를 컴퓨팅하지 않습니다. 3으로 인한 것입니다.

이 예에서는 너무 많은 일처럼 보일지 모르지만 그러한 일을 할 수 있다는 것은 질문이 반대하는 것처럼 좋은 힘입니다.

static_if 다음 버전의 C ++ (C ++ 1Y)에 대해 제안되었습니다. 원래 C ++ 11에 대해 제안되었지만 분명히 지연되었습니다.

제안서를 참조하십시오 여기. 흥미롭게도 저자 중 한 명은 D의 제작자 인 Walter Bright입니다.

또한, 컴파일러 해킹을 사용하여 현재 C ++에서 static-if를 속일 수 있습니다..

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top