C ++ - यहाँ 'टेम्प्लेट' कीवर्ड की आवश्यकता क्यों है?


9

मेरे पास निम्नलिखित कोड हैं:

template <typename TC>
class C
{
    struct S
    {
        template <typename TS>
        void fun() const
        {}
    };

    void f(const S& s)
    {
        s.fun<int>();
    }
};

// Dummy main function
int main()
{
    return 0;
}

जब इसे जीसी 9.2 और क्लैंग (9.0) दोनों के साथ बनाया जाता है, तो मुझे templateकीवर्ड को इनवॉइस करने के लिए आवश्यक संकलन त्रुटि मिल रही है fun। क्लेंग शो:

error: use 'template' keyword to treat 'fun' as a dependent template name
        s.fun<int>();
          ^
          template 

मुझे समझ में नहीं आता है कि संकलक funके संदर्भ में एक आश्रित नाम क्यों है f, क्योंकि fयह एक टेम्पलेट नहीं है। यदि मैं Cटेम्पलेट के बजाय एक नियमित वर्ग में बदल जाता हूं , तो त्रुटि दूर हो जाती है; हालाँकि, मैं नहीं देखता कि क्यों न तो पहली जगह में कोई त्रुटि हो Sऔर न ही fनिर्भर हो TC

ताज्जुब है, MSVC 19.22 यह सिर्फ ठीक संकलित करता है।


ध्यान दें

मतदान करने से पहले, मुझे कहां और क्यों "टेम्पलेट" और "टाइपनेम" कीवर्ड डालना है? कृपया विचार करें कि यह एक विशेष मामला है, भले ही Sवास्तव में एक आश्रित नाम हो, इस संदर्भ में fनिर्भर नहीं होगा यदि इस तथ्य के लिए नहीं कि वे वर्तमान तात्कालिकता के सदस्य हैं।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
भार्गव राव

जवाबों:


10

विचार करें :

template<typename T>
struct C
{
    struct S
    {
        int a = 99;
    };

    void f(S s, int i)
    {
        s.a<0>(i);
    }
};

template<>
struct C<long>::S
{
    template<int>
    void a(int)
    {}
};

int main()
{
    C<int>{}.f({}, 0); // #1
    C<long>{}.f({}, 0); // #2
}

s.a<0>(i)एक अभिव्यक्ति के रूप में दो तुलनात्मक संचालन <और >, और यह # 1 के लिए ठीक है, लेकिन # 2 के लिए विफल रहता है।

यदि इसे बदल दिया जाता है s.template a<0>(i)तो # 2 ठीक है और # 1 विफल हो जाता है। इस प्रकार यहां templateकीवर्ड कभी भी अनावश्यक नहीं है।

MSVC एक ही कार्यक्रम में दोनों तरीकों से अभिव्यक्ति की व्याख्या करने में सक्षम है s.a<0>(i)। लेकिन यह मानक के अनुसार सही नहीं है; प्रत्येक एक्सप्रेशन से निपटने के लिए कंपाइलर के लिए केवल एक पार्स होना चाहिए।


मैं अभी भी पूरी तरह से यह नहीं समझता। आपके उदाहरण से पता चलता है कि इस मामले में आप या तो एक विशेषज्ञ Cया दूसरे का उपयोग करते हैं, लेकिन आप कभी भी दोनों को तुरंत नहीं कर सकते। यहां templateकीवर्ड अभी भी IMHO से अप्रभावित है, क्योंकि जो Sउठाया जाता है वह उस पर निर्भर करता है जिस पर Cआप तुरंत काम करते हैं। templateकीवर्ड के बिना आप दोनों को तुरंत करने में सक्षम होंगे, और f का व्यवहार प्रत्येक उदाहरण के लिए अलग होगा।
मार्टिन

2
@Martin बिंदु यह है कि प्रत्येक टोकन के पास स्रोत फ़ाइल में केवल एक वाक्यविन्यास भूमिका होनी चाहिए। उदाहरण के लिए, टोकन के <लिए एक टेम्प्लेट इंस्ट्रूमेंटेशन में तुलना ऑपरेटर और दूसरे इंस्टेंटेशन में ओपनिंग एंगल ब्रैकेट होना ठीक नहीं है। यह सुनिश्चित करने के लिए है कि संकलक एक एएसटी को टेम्पलेट को पार्स कर सकते हैं (टेम्पलेट प्रकार के लिए प्लेसहोल्डर्स के साथ)।
इकतारा

यह समझ आता है। धन्यवाद!
मार्टिन

7

funटेम्प्लेट पैरामीटर के आधार पर टेम्पलेट फ़ंक्शन (या बिल्कुल मौजूद नहीं हो सकता है) हो सकता है या नहीं class C

ऐसा इसलिए है क्योंकि आप विशेषज्ञ S(बिना विशेषज्ञता के C) कर सकते हैं :

template <> struct C<int>::S {};

क्योंकि कंपाइलर जानना चाहता है कि क्या funकोई टेम्पलेट है या नहीं जब पहली बार class C(टेम्पलेट पैरामीटर को प्रतिस्थापित करने से पहले) templateकी आवश्यकता है।


1
मन ... उड़ा ...
बोलोव

इसके बाद अनुवर्ती, यह है कि क्या इन नई परिभाषाओं को Sकभी भी एक्सेस किया जा सकता है f। यदि वे नहीं कर सकते हैं, तो इस प्रतिबंध का कोई मतलब नहीं है क्योंकि fवे उन्हें वैसे भी नहीं देख पाएंगे।
मार्टिन

@Martin GCC, Clang और MSVC दोनों के साथ fहै।
१०:३१ पर पवित्रब्लैकैट

@bolov हाँ, आप विभिन्न चीजों के बहुत सारे विशेषज्ञ कर सकते हैं
होलीब्लैकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.