سؤال

أعتقد د 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.على سبيل المثال ليسب و نيميرل تتيح لك إنشاء التعليمات البرمجية التي يتوسع الماكرو لاستخدامها في إنشاءات البرمجة مثل "if" وحلقات for-loops.هذه هي في الأساس قرارات وقت الترجمة وتتيح لك القيام بشيء مشابه لـ if الثابتة.في حالة وحدات الماكرو Nemerle، فهي في الأساس عبارة عن مكونات إضافية للمترجم يتم تنفيذها في وقت الترجمة.

في 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 ومرفقها الماكرو - على وجه التحديد، 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)))

الآن ليس هناك حوسبة طول "فو"؛ انطالها كما 3.

قد يبدو الكثير من العمل في هذا المثال، ولكن القدرة على القيام بهذه الأشياء هي قوة جيدة لديك، كما يتخذ سؤالك.

static_if تم اقتراح الإصدار التالي من C ++ (C ++ 1Y). اقترح أصلا ل C ++ 11 ولكن يبدو أن تأخر على ما يبدو.

انظر الاقتراح هنا. وبعد ومن المثير للاهتمام، أحد المؤلفين هو Walter مشرق، خالق D.

أيضا، من الممكن المزيفة الثابتة - إذا كان في C ++ الحالية باستخدام المترجم الخارق.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top