لماذا القوالب C ++ اسمحوا لي الالتفاف أنواع غير مكتملة (الإعلانات إلى الأمام)؟

StackOverflow https://stackoverflow.com/questions/620378

سؤال

وحاولت ثلاث مرات التكرار لبرنامج بسيط التالية. هذا هو محاولة مبسطة للغاية لكتابة الزوج حاوية ومكرر من الطبقات، لكني لم اكن الوقوع في مشاكل مع أنواع غير مكتملة (الإعلانات إلى الأمام). اكتشفت أن هذا هو في الواقع من الممكن مرة واحدة templatized كل شيء - ولكن فقط إذا كنت فعلا المعلمة القالب! (أدركت هذا من خلال النظر في في جوجل كود sparsetable ).

وأي تلميحات يفسر لماذا يعمل الثانية في حين أن الثالث لا؟ (وأنا أعلم لماذا لا يعمل أول واحد - المترجم يحتاج إلى معرفة التخطيط الذاكرة من الحاوية.)

وشكرا مقدما.

// This doesn't work: invalid use of incomplete type.
#if 0
struct container;
struct iter {
  container &c;
  int *p;
  iter(container &c) : c(c), p(&c.value()) {}
};
struct container {
  int x;
  int &value() { return x; }
  iter begin() { return iter(*this); }
};
int main() {
  container c;
  c.begin();
  return 0;
}
#endif

// This *does* work.
template<typename T> struct container;
template<typename T> struct iter {
  container<T> &c;
  T *p;
  iter(container<T> &c) : c(c), p(&c.value()) {}
};
template<typename T> struct container {
  T x;
  T &value() { return x; }
  iter<T> begin() { return iter<T>(*this); }
};
int main() {
  container<int> c;
  c.begin();
  return 0;
};

// This doesn't work either.
#if 0
template<typename T> struct container;
template<typename T> struct iter {
  container<int> &c;
  int *p;
  iter(container<int> &c) : c(c), p(&c.value()) {}
};
template<typename T> struct container {
  int x;
  int &value() { return x; }
  iter<int> begin() { return iter<int>(*this); }
};
int main() {
  container<int> c;
  c.begin();
  return 0;
}
#endif
هل كانت مفيدة؟

المحلول

والأول يتطلب تعريف container منذ تقومون به عملية النسخ. إذا قمت بتعريف منشئ iter بعد تعريف container وتريد ان تكون بخير. لذلك:

struct container;
struct iter {
  container &c;
  int *p;
  iter(container &c);
};

struct container {
  int x;
  int &value() { return x; }
  iter begin() { return iter(*this); }
};

iter::iter(container &c) : c(c), p(&c.value()) {}

int main() {
  container c;
  c.begin();
  return 0;
}

ويعمل المثال الثاني لأنه لا يوجد الطبقة حتى كنت في الواقع مثيل واحد في وظيفة main الخاص بك. وبحلول ذلك الوقت يتم تعريف كافة أنواع. حاول نقل أي من تعريف iter أو القوالب container بعد الرئيسية وعليك ضرب خطأ.

والمثال الثالث هو التخصص لint أو هكذا يبدو. وهذا ينبغي أن تجميع لأنه لم يتم استخدام المعلمة القالب لiter. كنت قد حصلت على جملة التخصص قليلا قبالة. ومع ذلك، لا يوجد منشئ المناسبة لذلك عليك فقط الحصول على القمامة لx. وعلاوة على ذلك، على غرار المكررات جيدا من المؤشرات. سوف يمر قيمة this لن تكون ذات فائدة كبيرة. مطلوبة عادة المكررات لتسلسل وليس كائن فردي. رغم ذلك، لا يوجد شيء يمكن أن يمنعك من بناء واحد.

وأنت لا تحتاج إلى ; بعد وظيفة الجسم.

نصائح أخرى

هل يمكن أن تفعل ذلك دون قوالب عن طريق تحديد ايتر :: ايتر () بعد تعريف الحاوية:

struct container;

struct iter {
  container &c;
  int *p;
  iter(container &c);
};

struct container {
  int x;
  int &value() { return x; }
  iter begin() { return iter(*this); }
};

iter::iter(container &c)
    : c(c), p(&c.value()) {}

int main() {
  container c;
  c.begin();
  return 0;
}

ونسخة قالب يعمل لأنه عندما مثيل قوالب وتعرف كل من الطبقات تماما.

في الحالة الأولى، وأنت تحاول الوصول إلى وظيفة عضو في الطبقة الحاوية قبل أن يتم تعريف الفئة، وبالتالي فإن هذا لن ينجح.

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

في الحالة الثالثة هناك مرجع معاد. تستخدم حاوية ايتر وايتر يستخدم الحاويات، لذلك لا يمكن أن تعمل.

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