13

static ifDは興味深い言語機能だと思います。それは私の質問を促します.コンパイラがコードの強い概念を持ち、それらにアクセスするための言語機能があるコンパイル済み言語の他の例はありますか?

たとえば、次のコードはreprPythonと同様のものを提供します。

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

これは、このような機能と比較して、コードをより動的にするための裏返しの方法である、オーバーロードが行うことに対する別のより一般的なアプローチを可能にするため、これはクールだと思います。たとえば、コンパイラはクラスに含まれるフィールドの数を認識していますが、ほとんどの言語では、コードがコンパイル時にその情報にアクセスする方法がありません。

警告: 最後の段落には意見が含まれていましたが、論争を誘発するのではなく、私の質問の動機と説明を提供するつもりです。他のコンパイル済み言語にそのような機能があるかどうかを知りたいだけです。

4

3 に答える 3

10

実際のマクロを持つ言語には、静的なifの形式があります。たとえば、LispとNemerleを使用すると、マクロが「if」やforループなどのプログラミング構造を使用して展開するコードを構築できます。これらは基本的にコンパイル時の決定であり、静的な場合と同様のことを実行できます。Nemerleの場合、マクロは基本的にコンパイル時に実行されるコンパイラへのプラグインです。

C ++には、 2つのタイプから選択するために使用できる場合に一種の静的なブーストMPLライブラリがあります。run()メンバーの2つの型の中にコードを入れて、似たようなものを取得することもできますが、構文は非常に面倒です。

たとえば、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 */
}
于 2009-11-11T21:32:52.870 に答える
2

static_ifC++ の次のバージョン (C++1y) で提案されています。当初は C++11 向けに提案されていましたが、明らかに遅れていました。

ここで提案を参照してください。興味深いことに、著者の 1 人は、D の作成者であるウォルター ブライトです。

また、現在の C++ ではコンパイラ ハックを使用して static-if を偽造することもできます

于 2012-08-22T20:37:29.853 に答える
2

「言語のコード認識」に関しては、Lisp とそのマクロ機能、特に Common Lisp に勝るものはありません。しかし、ほとんどの場合、コンパイル時またはマクロ展開時にオブジェクトの型が不明であるというトレードがあります。リテラルの場合、型は既知であるため、オブジェクトがリテラルであるかどうかをテストし、そうである場合は型に基づいて 1 つの方法で処理し、検出された変数を準備する積極的なマクロの例を見つけることができます。実行時の型検査用。

これは、私が数年前に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バインドされ、ここでは variable にバインドされていることに注意してください#: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としてインライン化されています。

この例では大変な作業のように見えるかもしれませんが、あなたの質問が意見を述べているように、そのようなことができることは良い力です.

于 2009-11-21T22:23:11.147 に答える