2010-03-01 31 views
32

किसी कारण से मैंने सोचा कि C++ 0x ने std::initializer_list को ऐसे फ़ंक्शंस के लिए फ़ंक्शन तर्क के रूप में अनुमति दी है जो इस प्रकार से बनाए जा सकने वाले प्रकारों की अपेक्षा करते हैं, उदाहरण के लिए std::vector। लेकिन जाहिर है, यह काम नहीं करता है। क्या यह सिर्फ मेरा कंपाइलर है, या यह कभी काम नहीं करेगा? क्या यह संभावित अधिभार समाधान समस्याओं की वजह से है?std :: startizer_list फ़ंक्शन तर्क

#include <string> 
#include <vector> 

void function(std::vector<std::string> vec) 
{ 
} 

int main() 
{ 
    // ok 
    std::vector<std::string> vec {"hello", "world", "test"}; 

    // error: could not convert '{"hello", "world", "test"}' to 'std::vector...' 
    function({"hello", "world", "test"}); 
} 
+1

एक जीसीसी बग की तरह खुशबू निर्दिष्ट करना होगा। विशेष रूप से प्रकाश में 'vec'' शुरू करने के साथ '= {...}' ठीक काम करता है। तर्क पारित होने का अर्थ '= प्रारंभकर्ता 'जैसा ही होना चाहिए। (दोनों कॉपी प्रारंभिक है)। –

+0

वह '= {...} 'का उपयोग नहीं कर रहा है, बस' टी var {...} '। –

+0

@ पीटर: सी ++ 0x में दोनों;) –

उत्तर

54

जीसीसी में एक बग है। मानक यह मान्य बनाता है। इस

  • कैसे और क्या आरंभीकरण सामान्य रूप में किया जाता है

    सूचना के दो पहलू होते हैं: देखते हैं?

  • ओवरलोड रिज़ॉल्यूशन के दौरान प्रारंभिकरण का उपयोग कैसे किया जाता है, और इसकी लागत कितनी है?

पहला प्रश्न उत्तर 8.5 में उत्तर दिया गया है। दूसरे प्रश्न का उत्तर अनुभाग 13.3 में दिया गया है। उदाहरण के लिए, संदर्भ बाध्यकारी 8.5.3 और 13.3.3.1.4 पर संभाला जाता है, जबकि सूची प्रारंभिकता 8.5.4 और 13.3.3.1.5 में संभाली जाती है।

8.5/14,16:

आरंभीकरण कि बहस में और साथ ही प्रपत्र

T x = a; 

में होता है गुजर, समारोह वापसी, एक अपवाद (15.1) फेंक एक अपवाद हैंडलिंग (15.3), और कुल सदस्य प्रारंभिकरण (8.5.1) को प्रति-प्रारंभिक कहा जाता है।


प्रारंभकर्ताओं के अर्थशास्त्र निम्नानुसार हैं [...]: यदि प्रारंभकर्ता एक ब्रेसिड-इनिट-सूची है, तो ऑब्जेक्ट सूची-प्रारंभिक (8.5.4) है। तर्क के रूप में, और एक std::vector<std::string>function के पैरामीटर के रूप में -

जब उम्मीदवार function पर विचार, संकलक एक प्रारंभकर्ता सूची देखेंगे (यह सिर्फ एक व्याकरण निर्माण है जो अभी तक कोई प्रकार नहीं है!)। यह पता लगाने की क्या रूपांतरण की लागत है और हम अधिक भार के संदर्भ में इन परिवर्तित कर सकते हैं कि क्या, 13.3.3.1/5 कहते

13.3.3.1.5/1:

जब एक तर्क एक प्रारंभकर्ता सूची (8.5.4) है, यह एक अभिव्यक्ति नहीं है और विशेष नियम इसे पैरामीटर प्रकार में परिवर्तित करने के लिए लागू होते हैं।

13.3.3.1.5/3:

अन्यथा, यदि पैरामीटर 13.3.1 प्रति एक गैर कुल दसवीं और अधिभार संकल्प है।7 तर्क प्रारंभकर्ता सूची से टाइप एक्स के किसी ऑब्जेक्ट के प्रारंभिकरण को करने के लिए एक्स का एकमात्र सर्वश्रेष्ठ कन्स्ट्रक्टर चुनता है, निहित रूपांतरण अनुक्रम एक उपयोगकर्ता-डीफ़ेड रूपांतरण अनुक्रम है। 13.3.3.1 में उल्लिखित सिवाय इसके कि प्रारंभकर्ता सूची तत्वों को कन्स्ट्रक्टर पैरामीटर प्रकारों के रूपांतरण के लिए उपयोगकर्ता-डीआईएफएड रूपांतरणों की अनुमति है।

गैर कुल वर्ग Xstd::vector<std::string> है, और मैं नीचे एक बेहतरीन निर्माता यह पता लगाने जाएगा। पिछले शासन अनुदान हमें निम्नलिखित तरह के मामलों में उपयोगकर्ता निर्धारित रूपांतरण का उपयोग करने के लिए:

struct A { A(std::string); A(A const&); }; 
void f(A); 
int main() { f({"hello"}); } 

हम std::string को स्ट्रिंग शाब्दिक कन्वर्ट करने के लिए अनुमति दी जाती है, भले ही यह एक उपयोगकर्ता परिभाषित रूपांतरण की जरूरत है। हालांकि, यह एक और अनुच्छेद के प्रतिबंधों को इंगित करता है। 13.3.3.1 क्या कहता है?

13.3.3.1/4, जो एकाधिक उपयोगकर्ता परिभाषित रूपांतरणों को रोकने के लिए जिम्मेदार अनुच्छेद है। हम केवल सूची initializations पर दिखेगा:

हालांकि, जब एक उपयोगकर्ता के डी फाई नेड रूपांतरण समारोह [(या निर्माता)] द्वारा [...] 13.3.1.7 एक उम्मीदवार है कि जब प्रारंभकर्ता पास करने का तर्क पर विचार एक तर्क के रूप में सूचीबद्ध करें या जब प्रारंभकर्ता सूची में एक तत्व है और कुछ वर्ग एक्स या संदर्भ (संभवतः सीवी-क्वालीफाईड) के संदर्भ में एक्स को एक्स के कन्स्ट्रक्टर के अंतिम पैरामीटर के लिए माना जाता है, या [...], केवल मानक रूपांतरण अनुक्रम और इलिप्सिस रूपांतरण अनुक्रमों की अनुमति है।

सूचना है कि यह एक महत्वपूर्ण प्रतिबंध नहीं है: यदि यह इस बात के लिए नहीं थे, इसके बाद के संस्करण एक समान रूप से अच्छी तरह से रूपांतरण अनुक्रम स्थापित करने के लिए कॉपी-निर्माता का उपयोग कर सकते हैं, और प्रारंभ अस्पष्ट होगा। (उस नियम में "ए या बी और सी" के संभावित भ्रम की सूचना दें: इसका मतलब है "(ए या बी) और सी" - इसलिए हम केवल प्रतिबंधित हैं जब एक्स के एक निर्माता द्वारा कनवर्ट करने की कोशिश की जा रही है प्रकार X का पैरामीटर)।

हमें इस रूपांतरण को करने के लिए उपयोग किए जाने वाले रचनाकारों को एकत्रित करने के लिए 13.3.1.7 पर प्रतिनिधिमंडल हैं।

8.5.4/1: के सामान्य पक्ष 8.5 से शुरू जो हमें 8.5.4 को प्रत्यायोजित से इस पैरा के दृष्टिकोण चलो

सूची-प्रारंभ डायरेक्ट-प्रारंभ में होते हैं या कॉपी प्रारंभ संदर्भों कर सकते हैं; प्रत्यक्ष-प्रारंभिक संदर्भ में सूची-प्रारंभिकरण को डायरेक्ट-लिस्ट-प्रारंभिकरण कहा जाता है और प्रति-प्रारंभिक संदर्भ में सूची-प्रारंभिकता को कॉपी-सूची-प्रारंभिकरण कहा जाता है।

8.5.4/2:

एक निर्माता एक प्रारंभकर्ता-सूची निर्माता अगर इसकी-सी युक्तियां पैरामीटर प्रकार std::initializer_list<E> या संदर्भ की है करने के लिए संभवतः सीवी-quali कुछ प्रकार ई के लिए फाई एड std::initializer_list<E>, और या तो कोई हो रहा है अन्य पैरामीटर या अन्य सभी पैरामीटर में डिफ़ॉल्ट तर्क हैं (8.3.6)।

8.5.4/3:

एक वस्तु या प्रकार टी के संदर्भ की सूची-प्रारंभ डी फाई नेड इस प्रकार है: [...] अन्यथा, अगर टी एक वर्ग प्रकार है, कंस्ट्रक्टर्स माना जाता है। यदि टी में प्रारंभकर्ता-सूची निर्माता है, तो तर्क सूची में प्रारंभिक सूची को एक तर्क के रूप में शामिल किया गया है; अन्यथा, तर्क सूची में प्रारंभकर्ता सूची के तत्व होते हैं। लागू कन्स्ट्रक्टर को गणना की जाती है (13.3.1.7) और सबसे अच्छा अधिभार संकल्प (13.3) के माध्यम से चुना जाता है।

इस समय, T वर्ग प्रकार std::vector<std::string> है। हमारे पास एक तर्क है (जिसमें अभी तक कोई प्रकार नहीं है! हम केवल व्याकरणिक प्रारंभकर्ता सूची रखने के संदर्भ में हैं)। कंस्ट्रक्टर्स 13.3.1.7 के रूप में enumerated हैं:

[...] टी एक प्रारंभकर्ता-सूची निर्माता (8.5.4) है, तो तर्क सूची एक भी तर्क के रूप में प्रारंभकर्ता सूची के होते हैं; अन्यथा, तर्क सूची में प्रारंभकर्ता सूची के तत्व होते हैं। प्रति-सूची-प्रारंभिकरण के लिए, उम्मीदवार कार्य टी के सभी रचनाकार हैं। हालांकि, यदि एक स्पष्ट निर्माता चुना जाता है, तो प्रारंभिकता खराब हो जाती है।

हम केवल केवल उम्मीदवार के रूप में std::vector के प्रारंभकर्ता सूची पर विचार करेंगे, क्योंकि हम पहले से ही जानते दूसरों इसके खिलाफ जीत नहीं होगा या तर्क फिट नहीं होगा।

vector(initializer_list<std::string>, const Allocator& = Allocator()); 

अब, एक std::initializer_list<T> के लिए एक प्रारंभकर्ता सूची परिवर्तित (तर्क/पैरामीटर रूपांतरण की लागत को वर्गीकृत करने) के नियमों 13.3.3.1.5 में enumerated हैं:

जब एक यह निम्न हस्ताक्षर है तर्क एक प्रारंभकर्ता सूची (8.5.4) है, यह एक अभिव्यक्ति नहीं है और विशेष नियम इसे पैरामीटर प्रकार में परिवर्तित करने के लिए लागू होते हैं। [...] यदि पैरामीटर प्रकार std::initializer_list<X> है और प्रारंभकर्ता सूची के सभी तत्वों को पूरी तरह से एक्स में परिवर्तित किया जा सकता है, तो अंतर्निहित रूपांतरण अनुक्रम सूची के तत्व को X. में परिवर्तित करने के लिए आवश्यक सबसे खराब रूपांतरण है। यह रूपांतरण हो सकता है प्रारंभकर्ता-सूची कन्स्ट्रक्टर को कॉल के संदर्भ में भी उपयोगकर्ता-डीआईएफएड रूपांतरण

अब, प्रारंभकर्ता सूची सफलतापूर्वक परिवर्तित हो जाएगा, और रूपांतरण अनुक्रम एक उपयोगकर्ता परिभाषित रूपांतरण (char const[N] से std::string करने के लिए) है। ,

अन्यथा यदि टी std::initializer_list<E> की एक विशेषज्ञता है, जैसा कि नीचे वर्णित एक initializer_list वस्तु का निर्माण किया और से एक वस्तु का आरंभीकरण के लिए नियमों के अनुसार वस्तु प्रारंभ करने में प्रयोग किया जाता है: कैसे इस 8.5.4 पर विस्तृत है फिर से किया जाता है एक ही प्रकार की एक कक्षा (8.5)। (...)

देखें 8.5.4/4 कैसे इस अंतिम चरण के किया जाता है :)

+11

@ जोहान्स: पुhew! बहुत अच्छा! क्या आपने "मानक" याद किया है? :-) –

+10

श्री स्ट्रॉस्ट्रप ने अभी ईमेल के माध्यम से पुष्टि की है कि यह काम करना चाहिए :) – fredoverflow

+0

मैं पूरे दिन के लिए (ए या बी) और सी नियमों से उलझन में था जब तक कि मैं यह लेख नहीं देखता ... क्या यह अंग्रेजी में एक आम बात है कि इस तरह की सजा (ए या बी) और सी के रूप में पढ़ा जाएगा? – user534498

2

बेतकल्लुफ़, मुझे यकीन है कि नहीं कर रहा हूँ, लेकिन मुझे लगता है यहाँ क्या हो रहा है कि एक initializer_list को बदलने एक रूपांतरण है, और परिवर्तित कि वेक्टर के लिए एक और रूपांतरण है। यदि ऐसा है, तो आप केवल एक अंतर्निहित रूपांतरण की सीमा से अधिक हैं ...

3

यह इस तरह से काम करने के लिए लगता है:

function({std::string("hello"), std::string("world"), std::string("test")}); 

शायद यह एक संकलक बग है, लेकिन शायद आप कर रहे हैं बहुत सारे निहित रूपांतरण मांगना।

1

यह या तो एक कंपाइलर बग है या आपका कंपाइलर std :: startizer_list का समर्थन नहीं करता है। जीसीसी 4.5.1 पर परीक्षण किया गया और यह ठीक संकलित करता है।

1

आप अपने initializer_list के प्रकार

function(std::initializer_list<std::string>{"hello", "world", "test"}); 

गुड लक

+0

नहीं, हम नहीं करते हैं। यह एक कंपाइलर बग था। यह जवाब लिखने से पहले 4.5 साल स्पष्ट था। –

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