مشغل Typedef وostream لـ std::vector
سؤال
لقد قمت بإنشاء فئة كروموسوم والتي انتهى بها الأمر إلى كونها مجرد غلاف للمتجه باستخدام عامل تشغيل ostream، لذلك قررت أن أكتب ناقل typedef بدلاً من ذلك.ومع ذلك، أواجه مشكلة مع مشغل ostream القالب...هل هذه هي أفضل طريقة للقيام بذلك؟(لقد رأيت بعض الأساليب وفشلت في تشغيل أي منها)
template<typename G>
class Chromosome {
public:
typedef typename std::vector<G> type;
typedef typename std::pair<type *,type *> ptr_pair;
};
template<typename G> //line 19 below:
std::ostream& operator<<(std::ostream& os, const Chromosome<G>::type& chromosome) {
for(auto iter = chromosome.begin(); iter != chromosome.end(); ++iter)
std::cout << *iter;
return os;
}
في الوقت الحالي الخطأ الذي أتلقاه هو:
chromosome.h:19: error: expected unqualified-id before ‘&’ token
chromosome.h:19: error: expected ‘)’ before ‘&’ token
chromosome.h:19: error: expected initializer before ‘&’ token
هتافات.
المحلول
لسوء الحظ، لا توجد طريقة نظيفة للقيام بذلك لأن المترجم لا يمكنه استنتاج نوع الملف G
من اعلان الدالة
template<typename G>
std::ostream& operator<<(std::ostream& os, const typename Chromosome<G>::type& chromosome);
والسبب هو أنه إذا كنت متخصصا Chromosome
بالنسبة للأنواع المختلفة، قد ينتهي بك الأمر في موقف لا يستطيع فيه المترجم استنتاج ذلك بشكل لا لبس فيه G
.على سبيل المثال:
template <typename G> class Chromosome {
public:
typedef std::vector<G> type; // No typename needed here, BTW
};
template <> class Chromosome<int> {
public:
typedef std::vector<double> type;
};
الآن، ماذا سيحدث لو فعلت هذا؟
vector<double> v;
cout << v << endl;
لا يستطيع المترجم معرفة ما إذا كان G
يكون double
أو int
في هذه الحالة، لأن كليهما Chromosome<int>
و Chromosome<double>
يملك vector<double>
كنوعهم المتداخل.
لإصلاح ذلك، سيتعين عليك استخدام النوع بشكل صريح vector<G>
كالحجة:
template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome);
لسوء الحظ، لا توجد طريقة أفضل للقيام بذلك.إنه ليس عيبًا في اللغة حقًا، نظرًا لوجود سبب وجيه لمنعه، ولكنه في الواقع يمنعك من فعل ما تريد في هذا السياق.
نصائح أخرى
العضو typedef type
هو اسم تابع:معناها يعتمد على معلمة القالب G
.تحتاج إلى استخدام أ typename
لنقول للمترجم ذلك type
يسمي نوعاً:
const typename Chromosome<G>::type&
للحصول على الشرح الكامل، فكر في قراءة مقالة الأسئلة الشائعة حول Stack Overflow C++، مكان وضع "القالب" و"اسم النوع" على الأسماء التابعة.
كما يشير @templatetypedef في التعليقات، في حين أن هذا سيمكن من تجميع التعليمات البرمجية، إلا أنه لن "يعمل" للسماح لك بإدراج رمز std::vector<G>
في std::ostream
لأن type
هو في سياق غير استنتاجي.
أسهل طريقة للإعلان عن التحميل الزائد والحصول على السلوك المتوقع هي الاستخدام std::vector<G>
مباشرة كنوع الوسيطة:
template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome)