जीसीसी मुद्दा: बेस क्लास के सदस्य का उपयोग करना जो टेम्पलेट तर्क पर निर्भर करता है

निम्नलिखित कोड जीसीसी के साथ संकलित नहीं है, लेकिन विजुअल स्टूडियो के साथ करता है:

template  class A {
public:
    T foo;
};

template  class B: public A  {
public:
    void bar() { cout << foo << endl; }
};

मुझे त्रुटि मिलती है:

test.cpp: सदस्य फ़ंक्शन में? शून्य बी :: बार ()?:

     

test.cpp: 11: त्रुटि:? foo? इस दायरे में घोषित नहीं किया गया

लेकिन यह होना चाहिए! अगर मैं बार को बदलता हूं

void bar() { cout << this->foo << endl; }

तो यह करता है संकलित करता है, लेकिन मुझे नहीं लगता कि मुझे यह करना है। क्या सी ++ के आधिकारिक चश्मा में कुछ है कि जीसीसी यहां चल रहा है, या यह सिर्फ एक क्विर्क है?

0
ro fr bn
यह दो चरण नाम लुकअप के कारण होता है (जो सभी कंपाइलर डिफ़ॉल्ट रूप से उपयोग नहीं करते हैं)। इस समस्या के 4 समाधान हैं: 1) उपसर्ग <�कोड> ए <�टी> :: foo , 2) उपसर्ग का उपयोग करें यह-> foo , 3) एक :: foo , 4 का उपयोग करके एक कथन जोड़ें वैश्विक कंपाइलर का उपयोग करें स्विच करें जो अनुमोदित मोड को सक्षम बनाता है। इन समाधानों के पेशेवरों और विपक्ष का वर्णन
जोड़ा लेखक KarolaN, स्रोत

5 उत्तर

डेविड जॉयनेर का इतिहास था, यही कारण है।

The problem when compiling B is that its base class A is unknown from the compiler, being a template class, so no way for the compiler to know any members from the base class.

पहले के संस्करणों ने वास्तव में आधार टेम्पलेट वर्ग को पार्स करके कुछ अनुमान लगाया था, लेकिन आईएसओ सी ++ ने कहा कि यह अनुमान उन संघर्षों का कारण बन सकता है जहां नहीं होना चाहिए।

टेम्पलेट में बेस क्लास सदस्य का संदर्भ देने का समाधान यह (जैसा आपने किया था) का उपयोग करना है या विशेष रूप से बेस क्लास का नाम देना है:

template  class A {
public:
    T foo;
};

template  class B: public A  {
public:
    void bar() { cout << A::foo << endl; }
};

gcc मैन्युअल में अधिक जानकारी।

0
जोड़ा
एक ओर, उस तरह का अर्थ समझ में आता है। लेकिन दूसरी ओर, यह वास्तव में लंगड़ा लगता है। संकलक की आवश्यकता नहीं है यह जानने के लिए कि foo तब तक संदर्भित करता है जब तक कि टेम्पलेट तत्काल नहीं हो जाता है, उस बिंदु पर, यह foo सदस्य <�कोड> ए </कोड> में। सी ++ में इन अजीब कोने के मामलों में से बहुत सारे तरीके हैं।
जोड़ा लेखक Derek Park, स्रोत
हाँ, यह पूरी तरह से अस्वीकार्य है ... तत्काल से पहले नहीं पता? तो टेम्पलेट्स में सामान्य रूप से तत्काल के लिए प्रतीक्षा करें .. यह उसकी भावना है, नहीं? क्या झंझट है...
जोड़ा लेखक neu-rah, स्रोत

सी ++ का मुख्य कारण यहां कुछ भी नहीं मान सकता है कि आधार टेम्पलेट को बाद में एक प्रकार के लिए विशेषीकृत किया जा सकता है। मूल उदाहरण जारी रखना:

template<>
class A {};

B x; 
x.bar();//this will fail because there is no member foo in A
0
जोड़ा

यह gcc-3.4 में बदल गया। सी ++ पार्सर को उस रिलीज में बहुत अधिक सख्त मिला - spec के प्रति लेकिन विरासत या बहु-मंच कोड अड्डों वाले लोगों के लिए अभी भी परेशान है।

0
जोड़ा

वाह। सी ++ कभी भी मुझे अजीबता से आश्चर्यचकित नहीं करता है।

एक टेम्पलेट परिभाषा में, अयोग्य नाम अब एक निर्भर आधार के सदस्य नहीं पाएंगे (जैसा कि [temp.dep]/3 द्वारा निर्दिष्ट किया गया है C ++ मानक में)। उदाहरण के लिए,

template  struct B {
  int m;
  int n;
  int f ();
  int g ();
};
int n;
int g ();
template  struct C : B {
  void h ()
  {
    m = 0;//error
    f (); //error
    n = 0;//::n is modified
    g (); //::g is called
  }
};

You must make the names dependent, e.g. by prefixing them with this->. Here is the corrected definition of C::h,

template  void C::h ()
{
  this->m = 0;
  this->f ();
  this->n = 0
  this->g ();
}

As an alternative solution (unfortunately not backwards compatible with GCC 3.3), you may use using declarations instead of this->:

template  struct C : B {
  using B::m;
  using B::f;
  using B::n;
  using B::g;
  void h ()
  {
    m = 0;
    f ();
    n = 0;
    g ();
  }
};

यह सिर्फ पागल के सभी प्रकार है। धन्यवाद, डेविड।

मानक [आईएसओ/आईईसी 14882: 2003] का "temp.dep/3" खंड यहां दिया गया है कि वे इसका जिक्र कर रहे हैं:

क्लास टेम्पलेट या क्लास टेम्पलेट के सदस्य की परिभाषा में, यदि क्लास टेम्पलेट का बेस क्लास टेम्पलेट-पैरामीटर पर निर्भर करता है, तो बेस क्लास स्कोप की परिभाषा के बिंदु पर अयोग्य नाम लुकअप के दौरान जांच नहीं की जाती है कक्षा टेम्पलेट या सदस्य या कक्षा टेम्पलेट या सदस्य के तत्काल के दौरान। [उदाहरण:

typedef double A; 
template class B { 
    typedef int A; 
}; 
template struct X : B { 
    A a;//a has typedouble 
}; 

The type name A in the definition of X binds to the typedef name defined in the global namespace scope, not to the typedef name defined in the base class B. ] [Example:

struct A { 
    struct B { /* ... */ }; 
    int a; 
    int Y; 
}; 
int a; 
template struct Y : T { 
    struct B { /* ... */ }; 
    B b; //The B defined in Y 
    void f(int i) { a = i; }//::a 
    Y* p;//Y 
}; 
Y ya; 

The members A::B, A::a, and A::Y of the template argument A do not affect the binding of names in Y. ]

0
जोड़ा

वीसी दो चरण के लुकअप को लागू नहीं करता है, जबकि जीसीसी करता है। इसलिए जीसीसी तत्काल होने से पहले टेम्पलेट को पार करती है और इस प्रकार वीसी की तुलना में अधिक त्रुटियां पाती हैं। आपके उदाहरण में, foo एक आश्रित नाम है, क्योंकि यह 'टी' पर निर्भर करता है। जब तक आप संकलक को यह नहीं बताते कि यह कहां से आता है, यह टेम्पलेट की वैधता की जांच नहीं कर सकता है, इससे पहले कि आप इसे तुरंत चालू करें। यही कारण है कि आपको कंपाइलर को यह बताना होगा कि यह कहां से आता है।

0
जोड़ा