سؤال

أنا أستخدم مكتبة تتكون بالكامل تقريبًا الفئات والوظائف الملموسة في ملفات الرأس, ، مثله:

// foo.h
template<class T>
class Foo {
  Foo(){}
  void computeXYZ() { /* heavy code */ }
};
template<class T>
void processFoo(const Foo<T>& foo) { /* more heavy code */ }

الآن هذا سيء لأن أوقات التجميع لا تطاق كلما قمت بتضمين أحد ملفات الرأس هذه (وفي الواقع أقوم بتضمين العديد منها في كل وحدة من وحدات التجميع الخاصة بي).

نظرًا لأن معلمة قالب ، فأنا أستخدم نوعًا أو نوعين فقط على أي حال أخطط لإنشاء ، لكل ملف رأس مكتبة ، ملف يحتوي فقط على إعلانات, ، بدون الرمز الثقيل ، مثل هذا:

// NEW: fwd-foo.h
template<class T>
class Foo {
  Foo();
  void computeXYZ();
};
template<class T>
void processFoo(const Foo<T>& foo);

ثم ملف واحد ينشئ جميع الصور التي سأحتاجها. يمكن أن يكون هذا الملف جمعت بشكل منفصل مرة واحدة وإلى الأبد:

// NEW: foo.cpp
#include "foo.h"
template class Foo<int>;
template class Foo<double>;
template void processFoo(const Foo<int>& foo);
template void processFoo(const Foo<double>& foo);

الآن يمكنني أن أدرج فقط fwd-foo.h في الكود الخاص بي ولديهم أوقات ترجمة قصيرة. سأربط foo.o في نهايةالمطاف.

الجانب السلبي ، بالطبع ، هو أنه يجب علي إنشاء هذه جديدة fwd-foo.h و foo.cpp ملفات نفسي. وبالطبع إنها مشكلة في الصيانة: عندما يتم إصدار إصدار مكتبة جديد ، يجب أن أتكيف معها مع هذا الإصدار الجديد. هل هناك أي سلبيات أخرى؟

وسؤالي الرئيسي هو:

هل هناك أي فرصة يمكنني إنشاء هذه الملفات الجديدة ، خاصة fwd-foo.h, تلقائيا من الأصل foo.h؟ يجب أن أفعل ذلك للعديد من ملفات رأس المكتبة (ربما 20 أو نحو ذلك) ، وسيكون الحل التلقائي الأفضل خاصة في حالة إصدار إصدار مكتبة جديد وعلي القيام بذلك مرة أخرى مع الإصدار الجديد. هل أي أدوات متاحة لهذه المهمة؟

تعديل:

سؤال إضافي: كيف يمكن للدعم حديثًا extern الكلمة الرئيسية تساعدني في هذه الحالة؟

هل كانت مفيدة؟

المحلول

نحن نستخدم lzz الذي ينقسم ملف واحد إلى رأس ووحدة ترجمة منفصلة. بشكل افتراضي ، فإنه عادةً ما يضع تعريفات القالب في الرأس أيضًا ، ومع ذلك ، يمكنك تحديد أنك لا تريد حدوث ذلك.

لتظهر لك كيف يمكنك استخدامه ، ضع في اعتبارك ما يلي:

// t.cc
#include "b.h"
#include "c.h"

template <typename T> 
class A {
  void foo () {
    C c;
    c.foo ();
    b.foo ();
  }
  B b;
}

خذ الملف أعلاه ونسخه إلى ملف "t.lzz". ضع أي #تضمن توجيهات إلى كتل HDR $ و $ SRC حسب الضرورة:

// t.lzz
$hdr
#include "b.h"
$end

$src
#include "c.h"
$end

template <typename T> 
class A {
  void foo () {
    C c;
    c.foo ();
    b.foo ();
  }
  B b;
}

الآن أخيرًا ، قم بتشغيل LZZ على الملف الذي يحدد أنه يضع تعريفات القالب في الملف المصدر. يمكنك إما القيام بذلك باستخدام أ $ pragma في الملف المصدر ، أو يمكنك استخدام خيار سطر الأوامر "-TS":

سيؤدي هذا إلى إنشاء الملفات التالية:

// t.h
//

#ifndef LZZ_t_h
#define LZZ_t_h
#include "b.h"
#undef LZZ_INLINE
#ifdef LZZ_ENABLE_INLINE
#define LZZ_INLINE inline
#else
#define LZZ_INLINE       
#endif
template <typename T>
class A
{
  void foo ();
  B b;
};
#undef LZZ_INLINE
#endif

و:

// t.cpp
//

#include "t.h"
#include "c.h"
#define LZZ_INLINE inline
template <typename T>
void A <T>::foo ()
          {
    C c;
    c.foo ();
    b.foo ();
  }
#undef LZZ_INLINE

يمكنك بعد ذلك تشغيلها من خلال بعض أوامر GREP/SED لإزالة وحدات الماكرو لمساعد LZZ.

نصائح أخرى

حاول استخدام الرؤوس المسبقة. أعرف دعم GCC و MSVC هذه الميزة. الاستخدام هو محدد من البائع ، رغم ذلك.

لقد كنت أعمل على نفس القضية لفترة طويلة الآن. في الحل الذي تقترحه ، أنت تحدد فصول القالب مرتين. سيكون الأمر على ما يرام إذا كان يحدد نفس الأشياء (بنفس الترتيب) ، ولكن من المحتم أن تواجه مشاكل عاجلاً أم آجلاً.

ما توصلت إليه هو النظر في المشكلة في العكس. طالما أنك لست متخصصًا في تطبيقك ، فإنه يعمل بأمان.

يستخدم وحدات الماكرو ، التي يضطر Avois إلى تحديث وسيطات القالب في ملف التنفيذ (كن حذرًا ، إذا كنت ترغب في إضافة وسيطات القالب الافتراضية إلى الفصل).

// foo.h
#define FOO_TEMPLATE template<typename T>
#define FOO_CLASS Foo<T>

FOO_TEMPLATE
class Foo {
  Foo();
  void computeXYZ();
};

// foo_impl.h
#include "foo.h"
FOO_TEMPLATE
FOO_CLASS::Foo(){}

FOO_TEMPLATE
void FOO_CLASS::computeXYZ() { /* heavy code */ }

من خلال القيام بذلك ، فإنك تعمل بشكل أساسي بنفس الطريقة التي تعمل بها مع الفصول غير المسببة للتشويش (يمكنك القيام بنفس الشيء مع وظائف القالب ، بالطبع).

تحرير: حول الكلمة الرئيسية الخارجية في C ++ 0x

أعتقد أن الكلمة الرئيسية الخارجية في C ++ 0x ستساعد ، لكنها لن تحل كل شيء بطريقة سحرية!

من هذه المقالة,

قوالب خارجية

كل وحدة تقوم بتثبيت قالب إنشاء نسخة منه بشكل أساسي في رمز الكائن. بعد ذلك ، يعود الأمر إلى الرابط للتخلص من جميع رمز الكائن الزائد في المرحلة الأخيرة ، وبالتالي إبطاء دورة ارتباط التحرير الحرجة التي تشكل يوم المبرمج (أو في بعض الأحيان أحلام اليقظة). لدائرة قصيرة ، قامت مجموعة رمز الكائنات القمامة هذه ، حيث قام عدد من بائعي التحويل البرمجي بالفعل بتطبيق كلمة رئيسية خارجية يمكن أن تذهب أمام القوالب. هذه حالة من التقييس تدوين ممارسة الصناعة الحالية (المقصود التورية). في الممارسة العملية ، يتم تنفيذ ذلك عن طريق إرسال إشعار إلى المترجم بشكل أساسي "لعدم إنشاء هذا هنا":

extern template class std::vector;

سيقوم C ++ 0x بإصلاح مشكلات وقت الترجمة مع قوالب خارجية. لا أعرف طريقة تلقائية للقيام بما تطلبه.

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