وظيفة قالب إعلان النظام يؤثر على وضوح الرؤية (في بعض الأحيان)

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

سؤال

أحاول إنشاء وظيفة:

template <typename T>
void doIt( T*& p )
{
   if ( !p ) { return; }
   T& ref = *p;
   getClassName( ref );
}

حيث السلوك يختلف حسب نوع p مرت في.على وجه الخصوص, إصدار getClassName ودعا يجب أن تعتمد على نوع من p.في المثال التالي, أنا يمكن الاتصال بنجاح:

doIt<myClass1>( myClass1*& )
doIt<myClass1<int> >( myClass1*& )
doIt<myClass2>( myClass2*& )
doIt<myClass2<int> >( myClass2*& )

لكنه فشل عندما اتصل:

doIt< std::vector<int, std::allocator<int> > >( std::vector<int, std::allocator<int>>*& )

مع الخطأ:

a.cxx: In function ‘void doIt(T*&) [with T = std::vector<int, std::allocator<int> >]’:
ba.cxx:87:   instantiated from here
a.cxx:33: error: invalid initialization of reference of type ‘MyClass1&’ from expression of type ‘std::vector<int, std::allocator<int> >’
a.cxx:16: error: in passing argument 1 of ‘const char* getClassName(MyClass1&)’

(دول مجلس التعاون الخليجي 4.2.4).

إذا انتقلت إعلان:

template<typename T, typename A>
char const* getClassName( std::vector<T,A>& ) { printf("std::vector<T,A>\n"); return NULL; }

قبل doIt-ثم يجمع.لذلك ،

  • لماذا هو مطلوب أن getClassName( std::vector<T,A>& ) يظهر قبل doIt ولكن ليس getClassName( MyClass2T<T>& )
  • ما الذي يمكنني القيام به لجعل doIt مستقلة std::vector?(أريد أن أكون قادرة على المكان doIt في رأس الخاصة به وليس من الضروري أن تعرف عن std::vector, أو أي من التخصصات التي سيتم معرفة من قبل المستخدم).

.

#include <stdio.h>
#include <assert.h>
#include <vector>

//template<typename T>
//char const* getClassName( T& );

//template<typename T, typename A>
////char const* getClassName( std::vector<T,A>& ) { printf("std::vector<T,A>\n"); return NULL; }

#if 1
// ---------  MyClass2
struct MyClass1
{};

char const* getClassName( MyClass1& ) { printf("MyClass1\n"); return NULL; }

// ---------  MyClass1T
template< typename T>
struct MyClass1T
{};

template<typename T>
char const* getClassName( MyClass1T<T>& ) { printf("MyClass1T<T>\n"); return NULL; }
#endif


template <typename T>
void doIt( T*& p )
{
   if ( !p ) { return; }
   T& ref = *p;
   getClassName( ref );
}


// ---------  MyClass2
struct MyClass2
{};


// declared after doIt, OK.
char const* getClassName( MyClass2& ) { printf("MyClass2\n"); return NULL; }

// ---------  MyClass2T
template< typename T>
struct MyClass2T
{};

// declared after doIt, OK.
template<typename T>
char const* getClassName( MyClass2T<T>& ) { printf("MyClass2T<T>\n"); return NULL; }

template<typename T, typename A>
char const* getClassName( std::vector<T,A>& ) { printf("std::vector<T,A>\n"); return NULL; }



void test()
{
#if 1
   MyClass1 mc1;
   MyClass1* mc1p = &mc1;
   doIt( mc1p );

   MyClass2 mc2;
   MyClass2* mc2p = &mc2;
   doIt( mc2p );

   MyClass1T<int> mc1t;
   MyClass1T<int>* mc1tp = &mc1t;
   doIt( mc1tp );

   MyClass2T<int> mc2t;
   MyClass2T<int>* mc2tp = &mc2t;
   doIt( mc2tp );

   // Nested templates are OK.
   MyClass2T<MyClass1> mc2t2;
   MyClass2T<MyClass1>* mc2tp2 = &mc2t2;
   doIt( mc2tp2 );
#endif

#if 1
   std::vector<int> v;
   std::vector<int>* vp = &v;
   doIt( vp );                   // FAIL!
#endif
}
هل كانت مفيدة؟

المحلول

لماذا هو مطلوب أن getClassName( std::ناقلات& ) تظهر قبل doIt ولكن ليس getClassName( MyClass2T& )

الإعلان في نطاق مطلوب لأي وظيفة.عند إنشاء قالب وظيفة مع vector<int> وتتوقع وظيفة مع التوقيع getClassName(vector<int>&) أن تكون موجودة (على الأقل في النموذج) من أجل تجميع لتحقيق النجاح.

ماذا يمكنني أن أفعل لا تجعل doIt مستقلة من الأمراض المنقولة جنسيا::ناقل?(أريد أن تكون قادرة على وضع doIt في رأس الخاصة به ولا يجب أن تعرفه عن الأمراض المنقولة جنسيا::ناقلات ، أو أي من التخصصات التي سيتم معرفة من قبل المستخدم)

قراءة أسئلة وأجوبة على القوالب.محاولة وضع النموذج الأولي من كل من doIt's تعتمد وظائف القالب قبل أول مثيل من doIt.

نصائح أخرى

سبب الفشل هو أن في مثيل لا غير مؤهلين اسم بحث عن وظائف تحدث (ولكن فقط ADL - حجة يعتمد البحث).إنشاء مثيل السياق هو (مأخوذة من 14.6.4.1/6 C++ القياسية):

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

نقطة مثيل من كل تلك قالب التخصصات اتصلت في هذه الحالة هو فقط بعد تعريف test (قراءة 14.6.4.1/1).لذا, كل الوظائف التي أعلن مرئية في test وظيفة باستخدام المشروط في البحث ، ولكن البحث بالنسبة لهم هو في الواقع مختلف عن وظيفة المكالمات:

استدعاء دالة التي تعتمد على قالب المعلمة داخل القالب تبدو مثل هذا:

  • أسماء من تعريف القالب السياق تعتبر عادية بحث و ADL.
  • أسماء من مثيل السياق تعتبر فقط ADL.

وهذا يعني أن لأنه لا يوجد مناسبة getClassName وظيفة أعلن في تعريف سياق قالب مناسب وظيفة لديها في مثيل السياق باستخدام ADL - وإلا فإن الاتصال سوف تفشل و لا تجد أي إعلان.

حجة يعتمد البحث (ADL)

حجة من نوع std::vector<T>, ADL البحث عن وظائف في مساحة الاسم std و الاسم T.وضع getClassName وظيفة في std مساحة العمل على هذا (ولكن ذلك لا يسمح به معيار لأن ذلك ينتج أن السلوك غير معرف - ينبغي أن يتم ذلك إلا كملاذ أخير).

أن نرى آثار ADL محاولة استدعاء doIt مع ناقلات MyClass2 بدلا من int.منذ ذلك الحين T = MyClass2, ADL سيتم البحث في مساحة الاسم MyClass2 مناسبة وظيفة قبول std::vector<MyClass2> وسوف تنجح - مقابل عند استخدام int, والتي سوف ننظر فقط إلى std.

من أجل وظيفة أخرى المكالمات كل منهما الإعلانات كلها موجودة أيضا ، لأنها كلها أعلن في مساحة العالمي في حجة أنواع المكالمات وظيفة محددة جدا (MyClass1, MyClass2 وما إلى ذلك).

C++ التعليمات جيد, ولكن لا تذهب عميقا في قوالب (لم أجد أي ذكر العدل في ذلك).هناك مخصص قالب أسئلة وأجوبة الذي يتعامل مع بعض أكثر تعقيدا المزالق.


حذار من السلوك غير معرف

نلاحظ أن العديد من المجمعين لن تقبل قانون حتى عندما كنت وضعت هذا الإعلان عرضتها بعد على test وظيفة (وليس قبل ذلك).ولكن كما سبق القياسية اقتباس يقول ، ثم الإعلان لن يكون جزءا من مثيل السياق وحكم وجدت في 14.6.4.2/1 هو أن يكون شاهد:

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

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

ويساعد هذا الأمل.

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