2009-11-11 13 views
13

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

たとえば、次のコードは、Pythonから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); 
    } 
} 

を私はこれがクールだと思う、それは内部の一種である、どのようなオーバーロードに異なる、より一般的なアプローチが行うことができますのでですこのような機能と比較して、コードをよりダイナミックにする方法を示します。たとえば、コンパイラはクラスのフィールド数を知っていますが、ほとんどの言語でコンパイル時にその情報にアクセスする方法はありません。

警告:最後の段落には意見がありましたが、私は疑問の動機づけと明確化を提供するだけで、論争を誘発するものではありません。私はちょうど他のコンパイルされた言語がそのような機能を持っているかどうかを知りたい。

+1

多くのCおよびC++コンパイラは、コンパイル時に 'if'の式が判別できれば、未使用のコードを削除します。あなたの質問に完全に答えるかどうかは分かりません。 –

+0

いいえ - 静的なifの一部のブロックのコードが有効でないため、上記の例はコンパイルされません。例えば。 Tがint型の場合、value .__ repr __()はコンパイルエラーです。 – Grumdrig

+1

上記をコンパイルするには、「静的if(typeof(value .__ repr__))」)を作成する必要があります。または "静的if(__ traits(コンパイル、値.__ repr__))")。 – Baxissimo

答えて

10

実際のマクロを持つすべての言語は、静的ifの形式を持ちます。例えば、LispとNemerleは、マクロが 'if'やfor-loopsのようなプログラミング構造体を使って展開するコードを構築させます。これらは基本的にコンパイル時の決定であり、静的ifに似た何かをすることができます。 Nemerleの場合、マクロは基本的にコンパイル時に実行されるコンパイラへのプラグインです。

boost MPLライブラリにはkind of static ifがあり、2種類の中から選択することができます。 run()メンバに2つの型の中にいくつかのコードを入れて、似たようなものを得ることができますが、非常に面倒な構文です。だろうDで

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

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

美しい。ネメルは私には新しく、とても面白いです。それを探求することを楽しみにしています。私が考えていたはずのLispマクロ。 – Grumdrig

2

「コードの言語の意識」について、私はノー良くありますあなたはこのような何かを行うことができブーストMPLと例えば

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としてインライン化されています。

この例ではあまりにも多くの作業のように見えるかもしれませんが、そのようなことを行うことができることはあなたの質問opinesとして良い力です。

2

static_ifは、C++(C++ 1y)の次のバージョンで提案されました。もともとC++ 11のために提案されましたが、明らかに遅れました。

提案書を参照here。興味深いことに、作者の1人は、D.

また、it's possible to fake static-if in current C++ using compiler hacksの作成者であるWalter Brightです。

関連する問題