سؤال

وفي الواقع لقد مشكلة مع تجميع بعض المكتبات مع المترجم إنتل.

تم تجميع هذه المكتبة نفسها بشكل صحيح مع 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 الأمثلة.

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