قوالب مشكلة ( 'typename' لا قالب وظيفة معلمة)
-
05-07-2019 - |
سؤال
وفي الواقع لقد مشكلة مع تجميع بعض المكتبات مع المترجم إنتل.
تم تجميع هذه المكتبة نفسها بشكل صحيح مع g ++.
وهو سبب المشكلة بواسطة قوالب أخرى.
ما أود أن يفهم هو إعلان
**typename**
المعلمة وظيفة لا قالب وتعريف متغير داخل الجسم وظيفة
وعلى سبيل المثال:
void func(typename sometype){..
...
typename some_other_type;
..
}
وتجميع هذا النوع من المنتجات البرمجية التالية الأخطاء (إنتل)، (دول مجلس التعاون الخليجي لا يدعي): لقد حصلت أخطاء التالية
../../../libs/log/src/attribute_set.cpp(415): error: no operator "!=" matches these operands
operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'>
while (begin != end)
^
detected during instantiation of "void boost::log_st::basic_attribute_set<CharT>::erase(boost::log_st::basic_attribute_set<CharT>::iter<'\000'>, boost::log_st::basic_attribute_set<CharT>::iter<'\000'>) [with CharT=wchar_t]" at line 438
../../../boost/log/attributes/attribute_set.hpp(115): error: no operator "!=" matches these operands
operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'>
if (it != m_pContainer->end())
وماذا أريد أن أفهم هو استخدام على TypeName داخل الجسم من الوظائف والإعلانات المعلمة.
ومثلا:
template< typename CharT >
struct basic_attribute_values_view< CharT >::implementation
{
public:
..
..
void adopt_nodes( **typename attribu**te_set_type::const_iterator& it, **typename attribut**e_set_type::const_iterator end)
{
for (; it != end; ++it)
push_back(it->first, it->second.get());
}
وفي ملف مختلف لدي:
template< typename CharT >
class basic_attribute_set
{
friend class basic_attribute_values_view< CharT >;
//! Self type
typedef basic_attribute_set< CharT > this_type;
public:
//! Character type
typedef CharT char_type;
//! String type
typedef std::basic_string< char_type > string_type;
//! Key type
typedef basic_slim_string< char_type > key_type;
//! Mapped attribute type
typedef shared_ptr< attribute > mapped_type;
//! Value type
typedef std::pair< const key_type, mapped_type > value_type;
//! Allocator type
typedef std::allocator< value_type > allocator_type;
//! Reference type
**typedef typename allocator_type::reference reference;**
المحلول
وتحتاج إلى استخدام typename
لما يسمى "أنواع تعتمد". تلك هي الأنواع التي تعتمد على حجة القالب وليس من المعروف حتى يتم إنشاء مثيل القالب. على الارجح أفضل تفسير ذلك باستخدام مثال:
struct some_foo {
typedef int bar;
};
template< typename Foo >
struct baz {
typedef Foo::bar barbar; // wrong, shouldn't compile
barbar f(); // would be fine if barbar were a type
// more stuff...
};
وهذا typedef
تحديد barbar
واحد هو أن يتطلب typename
حتى يتسنى للمترجم أن تكون قادرة على التحقق من القالب عن الأخطاء النحوية الصارخة <م> قبل م> مثيل مع نوع ملموس. والسبب هو أنه عندما يرى المترجم القالب لأول مرة (عندما لا مثيل مع المعلمات قالب ملموسة حتى الآن)، والمترجم لا يعرف ما إذا Foo::bar
هو نوع. لكل ما تعرف، وأنا قد baz
نية لإنشاء مثيل مع أنواع مثل هذا واحد
struct some_other_foo {
static int bar;
};
في هذه الحالة Foo::bar
أن يشير إلى كائن <م> م>، وليس نوع، وتعريف baz::bar
سيكون هراء النحوي. دون معرفة ما إذا كانت Foo::bar
يشير إلى نوع المحول البرمجي لا يوجد لديه فرصة للتحقق أي شيء داخل baz
هذا ما تستخدم مباشرة أو غير مباشرة barbar
حتى لالأخطاء المطبعية أغبى حتى يتم إنشاء مثيل baz
. باستخدام typename
السليم، baz
يبدو مثل هذا:
template< typename Foo >
struct baz {
typedef typename Foo::bar barbar;
barbar f();
// more stuff...
};
والآن مترجم على الأقل يعرف من المفترض أن يكون اسم نوع، الأمر الذي يجعل Foo::bar
اسم نوع أيضا أن barbar
. حتى إعلان f()
هو موافق بنائي أيضا.
وبالمناسبة، هناك مشكلة مشابهة مع القوالب بدلا من أنواع:
template< typename Foo >
struct baz {
Foo::bar<Foo> create_wrgl(); // wrong, shouldn't compile
};
عند "يرى" المترجم Foo::bar
أنها لا تعرف ما هو عليه، لذلك bar<Foo
يمكن أن يكون مجرد وكذلك المقارنة، وترك مترجم الخلط حول >
زائدة. هنا، أيضا، تحتاج إلى إعطاء مترجم إشارة إلى أن Foo::bar
من المفترض أن يكون اسم قالب:
template< typename Foo >
struct baz {
Foo::template bar<Foo> create_wrgl();
};
وحذار: البصرية والجدير بالذكر C ++ لا يزال لا تنفيذ السليم مرحلتين البحث (في جوهره: أنها لا تحقق فعلا القوالب حتى يتم إنشاء مثيل هم). لذلك فإنه غالبا ما يقبل كود الخاطئ بأن يفتقد typename
أو template
.
نصائح أخرى
وهذه النقطة من الكلمة typename
هو أن نقول للمترجم أن شيئا ما هو typename، في الحالات التي ليست واضحة. خذ هذا المثال:
template<typename T>
void f()
{
T::foo * x;
}
هل T::foo
نوع، وهذا يعني أننا اعلان المؤشر، أو هو T::foo
متغير ثابت، ونحن نقوم الضرب؟
ومنذ مترجم لا يوجد لديه فكرة عما T يمكن أن يكون في الوقت الذي يقرأ القالب، فإنه لا يوجد لديه فكرة أي من الحالتين هو الصحيح.
والمعيار يقتضي أن المترجم يجب أن تحمل هذه الحالة الأخيرة، وتفسير T::foo
باعتباره typename إلا إذا سبقتها قبل الكلمة typename
، مثل هذا:
template<typename T>
void f()
{
typename T::foo* x; //Definitely a pointer.
}
وعند التعليمات البرمجية:
void func(typename sometype)
{
.....typename some_other_type;
..
}
إذا رمز أعلاه ليست جزءا من القالب، ثم انه لا يمكن التعامل معه بلغة ++ ز، ما لم الإصدار القديم من ز ++.
وكما بلدي من ذوي الخبرة، FC9 أو GNU C / ++ الإصدار 4.2x سيقدم تقريرا بأنها خطأ، وأنها سوف يشكو:
typename only can be used in template code
وحين FC8 أو GNU C / ++ 4.1x لا يجوز.
ويرجى الاطلاع على
http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/ringed_inl.h
and
http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/cont_inl.h
لمزيد من القالب وtypename الأمثلة.