2013-03-19 11 views
12

मान लीजिए हम निम्नलिखित कोड है:टेम्पलेट्स में शाब्दिक स्ट्रिंग - compilers के विभिन्न व्यवहार

template <typename T> 
void foo(const T&); 

int main() 
{ 
    foo("str"); 
} 

Demonstration

जीसीसी 4.7.2, बजना 3.2, आईसीसी 13.0.1

`शून्य foo < चार [4]> (चार स्थिरांक को

अपरिभाषित संदर्भ (&) [4]) '

MSVC-11,0

अनसुलझे बाह्य प्रतीक "शून्य __cdecl foo < चार स्थिरांक [4]> (चार स्थिरांक (&) [4]) "(?? $ foo @ BY03 $$ सीबीडी @@ YAXAAY03 $$ सीबीडी @ जेड $$)

सूचना char[4] पहले उत्पादन और दूसरी ओ में char const[4] में utput।

क्यों? और कौन सही है? क्या आप मानक उद्धृत कर सकते हैं, कृपया?

+7

दोनों शिकायत कर रहे हैं कोई 'foo' परिभाषित .... – UmNyobe

+0

@UmNyobe: स्ट्रिंग शाब्दिक "str" भी टाइप char const[4], Tchar [4], जिसका अर्थ है होना करने के लिए निष्कर्ष निकाला जाना चाहिए कि जीसीसी सही है के बाद से हाँ, मुझे पता है, यह टाइप केवल – FrozenHeart

+0

@UmNyobe मेरा मतलब है कि किस प्रकार इस मामले में होना चाहिए मुद्रित करने के लिए की जरूरत थी - चार [4] या चार स्थिरांक [4]? – FrozenHeart

उत्तर

1

जीसीसी सही है; कि वी.एस. के टेम्पलेट तर्क सूची में const वहां नहीं होना चाहिए:

[C++11: 14.8.2/3]: के बाद इस प्रतिस्थापन किया जाता है, समारोह पैरामीटर प्रकार 8.3.5 में वर्णित समायोजन किया जाता है। [उदाहरण:“void()(const int, int[5])” का एक पैरामीटर प्रकार “void(*)(int,int*)” हो जाता है। अंत उदाहरण][नोट: एक समारोह पैरामीटर घोषणा में एक उच्च-स्तरीय क्वालीफायर समारोह प्रकार प्रभावित नहीं करता है, लेकिन अभी भी समारोह के भीतर समारोह पैरामीटर चर के प्रकार प्रभावित करता है। अंत टिप्पणी][उदाहरण:

template <class T> void f(T t); 
template <class X> void g(const X x); 
template <class Z> void h(Z, Z*); 

int main() { 
    // #1: function type is f(int), t is non const 
    f<int>(1); 

    // #2: function type is f(int), t is const 
    f<const int>(1); 

    // #3: function type is g(int), x is const 
    g<int>(1); 

    // #4: function type is g(int), x is const 
    g<const int>(1); 

    // #5: function type is h(int, const int*) 
    h<const int>(1,0); 
} 

अंत उदाहरण]

(उदाहरण 4 उचित एक है।)

[C++11: 14.8.2/5]:जिसके परिणामस्वरूप प्रतिस्थापित और समायोजित फ़ंक्शन प्रकार का उपयोग एफ के प्रकार के रूप में किया जाता है टेम्पलेट तर्क कटौती के लिए एकीकरण टेम्पलेट।[..]

इसके अलावा

संभवतः प्रासंगिक:

एक समारोह कॉल से टेम्पलेट तर्क बात का अनुमान लगाना
[C++11: 14.8.2.1/2]: तो P एक संदर्भ प्रकार नहीं है:

  • तो A एक सरणी प्रकार है , सरणी-से-पॉइंटर मानक रूपांतरण (4.2) द्वारा उत्पादित सूचक प्रकार का उपयोग किया जाता है प्रकार की कटौती के लिए A; अन्यथा,
  • तो A एक समारोह का प्रकार, सूचक प्रकार समारोह करने के लिए सूचक मानक रूपांतरण (4.3) द्वारा उत्पादित प्रकार कटौती के लिए A के स्थान पर प्रयोग किया जाता है; अन्यथा,
  • तो A एक सीवी योग्य प्रकार, शीर्ष स्तर सीवी-क्वालिफायरA के प्रकार के
+1

हम सभी इसे जानते हैं, लेकिन सवाल के मामले में यह कैसे लागू होता है? –

+0

@JamesKanze: 'const' फ़ंक्शन प्रकार का हिस्सा नहीं है, और फ़ंक्शन प्रकार टेम्पलेट तर्क कटौती के लिए उपयोग किया जाता है। इस प्रकार, इस मामले में 'टी'' const' नहीं होगा, फिर भी ओपी के उदाहरण में एमएसवीसी ने ऐसा किया है। –

+0

मुझे लगता है कि मुझे कुछ कदम याद आ रहे हैं। :(सोचा था कि मैं इसे वहां फेंक दूंगा, हालांकि –

5

जीसीसी सही है प्रकार कटौती के लिए नजरअंदाज कर दिया जाता है। एक से थोड़ा सरल उदाहरण से

आइए शुरू, और बाद में साबित होता है कि मूल उदाहरण एक ही पैटर्न इस प्रकार है:

template<typename T> 
void bar(T const&) 
{ 
    // Shall not fire 
    static_assert(std::is_same<T, int>::value, "Error!"); 
} 

int main() 
{ 
    int x = 0; 
    bar(x); // 1 - Assertion won't fire 

    int const y = 0; 
    bar(y); // 2 - Assertion won't fire 
} 

यहाँ क्या हो रहा है? सबसे पहले, प्रति § 14.8.2.1/3:

[...] यदि पी संदर्भ प्रकार है, तो पी द्वारा संदर्भित प्रकार का प्रकार कटौती के लिए उपयोग किया जाता है। [...]

इसका मतलब यह है कि प्रकार कटौती और int const के खिलाफ (मामले 2 में) (मामले 1 में) int के खिलाफ T const बनाने का प्रयास करेगा। दूसरे मामले में, T के लिए int को प्रतिस्थापित करने से एक परिपूर्ण मिलान मिलेगा, इसलिए यह आसान है; पहले मामले में, हमारे पास const एक परिपूर्ण मिलान करने के लिए हमारे रास्ते पर जा रहा है। लेकिन यह वह जगह है जहां § 14.8.2.1/4 खेलने में आता है:

[...] मूल पी एक संदर्भ प्रकार है, तो निष्कर्ष निकाला एक (यानी, प्रकार संदर्भ द्वारा कहा गया है) हो सकता है अधिक सीवी योग्य तब्दील ए से [...]

यहाँ, की जगह T के लिए int हमें एक निष्कर्ष निकाला int const, जो और अधिक सीवी योग्य से int (के प्रकार है देता है तर्क x)। लेकिन यह उपरोक्त § 14.8.2.1/4 के कारण स्वीकार्य है, इसलिए इस मामले में भी Tint होने के लिए घटाया गया है।

चलो अब अपने मूल उदाहरण से निपटने (बस थोड़ा सा समायोजित, लेकिन हम मूल संस्करण के अंत में मिल जाएगा):

template<typename T> 
void bar(T const&) 
{ 
    // Does not fire in GCC, fires in VC11. Who's right? 
    static_assert(std::is_same<T, char[4]>::value, "Error!"); 
} 

int main() 
{ 
    char x[] = "foo"; 
    bar(x); 

    char const y[] = "foo"; 
    bar(y); 
} 

अलावा तथ्य यह है कि मैं char [] साथ int प्रतिस्थापित से, इस उदाहरण है और मेरी पहला उदाहरण संरचना में समान हैं। क्यों इस तुल्यता रखती है देखने के लिए, (है, जो पर आग नहीं करता है किसी भी संकलक की उम्मीद के रूप में) नीचे दावे पर विचार करें: पैरा में

// Does not fire 
static_assert(
    std::is_same< 
     std::add_const<char [4]>::type, 
     char const[4] 
    >::value, "Error"); 

सी ++ 11 स्टैंडर्ड जनादेश इस व्यवहार 3.9.3/2 :

किसी भी सीवी-क्वालिफायर एक सरणी प्रकार के लिए लागू किया सरणी तत्व प्रकार, नहीं सरणी प्रकार (8.3.4) प्रभावित करते हैं।

पैरा 8.3.4/1 भी निर्दिष्ट करता है:

[...] फार्म "NT के सीवी-क्वालीफायर-सेक सरणी" किसी भी प्रकार की "एन सीवी की सरणी लिए निकाला जाता है -क्वालिफायर-सेक टी ", और इसी तरह" टी के अज्ञात बंधन की सरणी "के लिए। सरणी के लिए वैकल्पिक विशेषता-विनिर्देशक-सीईसी appertains। [उदाहरण:

typedef int A[5], AA[2][3]; 
typedef const A CA; // type is “array of 5 const int” 
typedef const AA CAA; // type is “array of 2 array of 3 const int” 

अंत उदाहरण] [ध्यान दें: एक "एन सीवी-क्वालीफायर-सेक टी की सरणी" सीवी योग्य प्रकार है; 3.9.3 देखें। -जेंड नोट]

चूंकि अब यह स्पष्ट है कि दो उदाहरण समान पैटर्न प्रदर्शित करते हैं, यह एक ही तर्क लागू करने के लिए समझ में आता है। और यह हमें एक ही तर्क पथ के माध्यम से नेतृत्व करेंगे।

टाइप कटौती करते समय, T const पहले मामले में char[4] और दूसरे मामले में char const[4] के विरुद्ध मेल खाता है।

दूसरे मामले में, T = char[4] एक सही मैच पैदा करता है, क्योंकि प्रतिस्थापन के बाद T constchar const[4] बन जाता है। पहले मामले में, निष्कर्ष निकाला A एक बार फिर से अधिक है कि T पैदावार char const[4] के लिए char[4] प्रतिस्थापन में सीवी योग्य मूल A से है। लेकिन फिर, इसे 14.8.2.1/4 तक अनुमति है, इसलिए T को char[4] के रूप में घटाया जाना चाहिए।

अंत में, अपने मूल उदाहरण के लिए।

template<typename T> 
void foo(T const&) 
{ 
    // Shall not fire 
    static_assert(std::is_same<T, char[4]>::value, "Error!"); 
} 

int main() 
{ 
    foo("str"); // Shall not trigger the assertion 
} 
+0

लेकिन 'std :: add_const :: टाइप' 'char const [4]' जैसा ही है? यह स्पष्ट प्रतीत नहीं होता है - पहला 4 वर्णों का एक आधार सरणी है, जबकि दूसरा 4 कॉन्स वर्णों की सरणी है। – interjay

+0

@interjay: C++ 11 मानक के 3.9.3/2 देखें: "[...] किसी भी प्रकार के सीवी-क्वालीफायर किसी सरणी प्रकार पर लागू होते हैं, सरणी प्रकार (8.3.4) नहीं, सरणी तत्व प्रकार को प्रभावित करते हैं।" –

+0

@interjay: मैंने अपने उत्तर के अंतिम अपडेट में इस पर थोड़ा सा विस्तार किया –

संबंधित मुद्दे