13

我认为 Dstatic if是一个有趣的语言特性。这引发了我的问题:是否还有其他编译语言的示例,其中编译器对代码有很强的概念并且有语言工具可以访问它们?

例如,此代码提供了与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);
  }
}

我认为这很酷,因为它允许对重载所做的工作采用不同且更通用的方法,与此类功能相比,这是一种使代码更具动态性的由内而外的方式。例如,编译器知道我的类有多少个字段,但在大多数语言中,我的代码无法在编译时访问这些信息。

CAVEAT:最后一段有意见,但我只是想为我的问题提供一些动力和澄清,而不是引起争议。我只是想知道是否有任何其他编译语言具有此类功能。

4

3 回答 3

10

任何具有真正宏的语言都有静态 if 的形式。例如,Lisp 和Nemerle允许您使用“if”和 for 循环等编程结构来构建宏扩展为的代码。这些本质上是编译时的决定,让你做一些类似于静态 if 的事情。在 Nemerle 的情况下,宏基本上是编译器的插件,在编译时执行。

在 C++ 中有boost 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 */
}
于 2009-11-11T21:32:52.870 回答
2

对于“语言的代码意识”,我见过的没有比 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)

在中间?那是在宏扩展时检查第一个参数,并且根据参数是文字还是符号,它的类型可能是已知的,也可能是未知的。如果类型是一个符号,我们假设我们应该等到运行时重新考虑它是一个指向其他值的变量。

这是表单的扩展(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。

在这个例子中看起来工作量太大了,但是正如你的问题所认为的那样,能够做这些事情是一种很好的能力。

于 2009-11-21T22:23:11.147 回答
2

static_if已被提议用于下一版本的 C++ (C++1y)。它最初是为 C++11 提出的,但显然被推迟了。

请参阅此处的建议。有趣的是,其中一位作者是 D.

此外,在当前的 C++ 中,可以使用 compiler hacks 来伪造 static-if

于 2012-08-22T20:37:29.853 回答