Вопрос

Я думаю static if интересная языковая особенность. Это подсказывает мой вопрос: существуют ли другие примеры скомпилированных языков, на которых компилятор имеет сильное представление о коде, и есть средства для доступа к ним языкам?

Например, этот код предоставляет что -то похожее на repr от Python:

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);
  }
}

Я думаю, что это круто, потому что это позволяет другой и более общий подход к тому, что делает перегрузка, что является своего рода внутренним способом сделать код более динамичным по сравнению с такими функциями. Например, компилятор знает, сколько полей имеет у моего класса, но у моего кода нет возможности получить доступ к этой информации во время компиляции на большинстве языков.

Предостережение: этот последний абзац имел в нем мнения, но я просто хочу дать некоторую мотивацию и разъяснения для моего вопроса, а не выявлять противоречие. Я просто хочу выяснить, есть ли какие -либо другие скомпилированные языки такие функции.

Это было полезно?

Решение

Любой язык с настоящими макросами имеет форму статической, если. Например, LISP и Немерле Позвольте вам построить код, который макрос расширяется для использования программирующих конструкций, таких как «if» и для петли. Это по сути решения о компиляции и позволяют вам делать что-то похожее на статическое, если. В случае с немерией макросы в основном подключаются к компилятору, которые выполняются во время компиляции.

В C ++ есть повысить MPL библиотека, в которой есть своего рода статическое, если Это можно использовать для выбора между двумя типами. Вы можете поместить некоторый код внутри двух типов в члене 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 и его макросмерка - в частности, Common LISP. Но торговля существует такая часть времени, когда тип объекта не известен во время компиляции или времени макроэкспрессии. Для литералов известны типы, поэтому вы можете найти примеры агрессивных макросов, которые испытывают, чтобы увидеть, является ли объект буквальным, и, если это так, обрабатывать его в одну сторону - возможно, на основе его типа - и в противном случае подготовить обнаруженную переменную Для проверки типа времени.

Вот пример, который я адаптировал из Пособие Библиотека (часть Клок Библиотека) Несколько лет назад. Цель состоит в том, чтобы предоставить функции, которые оттолкнут строку префикса от какой -либо другой строки подходящим префиксом. Префикс может быть известен во время макроэкспрессии, или это не может. Если это так, мы можем оптимизировать: сначала вычислить длину префикса и встроить ее в качестве буквального, чтобы она не была пересказывана на каждом вызове с генерируемой функцией. Сначала макрос пугает, но фактический сгенерированный код невелик.

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

Также, Можно подделить статику IF в текущем C ++ с помощью хаков компилятора.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top