2012-10-01 10 views
5

क्या यह प्रोग्राम कानूनी है?क्या सूची-प्रारंभिकरण के माध्यम से उपयोगकर्ता द्वारा परिभाषित रूपांतरण फ़ंक्शन को आमंत्रित करना संभव है?

struct X { X(const X &); }; 
struct Y { operator X() const; }; 

int main() { 
    X{Y{}}; // ?? error 
} 

n2672 के बाद, और के रूप में defect 978 द्वारा संशोधित, 13.3.3.1 [over.best.ics] है:

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

यह बदले में लगता है; यह नतीजा यह है कि एक रूपांतरण एक सूची-प्रारंभ कलाकारों का उपयोग कर निर्दिष्ट करने अवैध है:

void f(X); 
f(Y{});  // OK 
f(X{Y{}}); // ?? error 

मैं समझता हूँ के रूप में n2640, सूची-प्रारंभ डायरेक्ट-आरंभीकरण के सभी उपयोगों की जगह और उसकी प्रतिलिपि प्रारंभ करने में सक्षम माना जाता है, लेकिन वहाँ केवल का उपयोग कर प्रकार Y का एक उद्देश्य से प्रकार X की एक वस्तु के निर्माण के लिए कोई रास्ता नहीं लगती सूची-प्रारंभ:

X x1(Y{}); // OK 
X x2 = Y{}; // OK 
X x3{Y{}}; // ?? error 

इस मानक के वास्तविक आशय है; यदि नहीं, तो इसे कैसे पढ़ा या पढ़ा जाना चाहिए?

+2

सूची प्रारंभिकरण _not_ प्रत्यक्ष प्रारंभिकरण के सभी उपयोगों को प्रतिस्थापित करने और प्रारंभिक प्रतिलिपि बनाने में सक्षम होना चाहिए। हमें यह जानने की जरूरत है कि जो भी इस गलतफहमी को फैल रहा है।:/ –

+0

अधिक भ्रमित बात यह है कि एक ही मार्ग से, 'एक्स x2 = वाई {};' भी अवैध होना चाहिए, क्योंकि यह 13.3.1.3 भाग के अंतर्गत आता है ("जब अस्थायी की प्रतिलिपि/स्थानांतरण के लिए कहा जाता है कक्षा प्रति-प्रारंभिकरण का दूसरा चरण ")। यह संभावना है कि यहां कुछ और चल रहा है। –

+0

@ निकोलबोलस मुझे लगता है कि कक्षा प्रति-प्रारंभ में पहला कदम रूपांतरण ऑपरेटर का उपयोग एक (अस्थायी) एक्स प्राप्त करने के लिए करना होगा, और उस एक्स से प्रतिलिपि करने का दूसरा चरण। या कम से कम यह है कि मैंने इसे कैसे पढ़ा। .. – fgp

उत्तर

2

एक्सकोड 4.4 के साथ भेजे गए क्लैंग 3.1 का संस्करण आपकी व्याख्या के साथ सहमत है और X{Y{}}; को अस्वीकार करता है। जैसा कि मैं करता हूं, मानक के प्रासंगिक भागों को कुछ बार फिर से पढ़ने के बाद, FWIW।

यदि मैं X के कन्स्ट्रक्टर को दो तर्क लेने के लिए संशोधित करता हूं, तो const X& टाइप करें, क्लैंग Y y; X{y,y} कथन स्वीकार करता है। (अगर मैं X{Y{},Y{}} कोशिश करता हूं तो यह दुर्घटनाग्रस्त हो जाता है ...)। यह 13.3.3.1p4 के साथ संगत प्रतीत होता है जो उपयोगकर्ता-परिभाषित रूपांतरणों को केवल एकल-तत्व मामले के लिए छोड़ने की मांग करता है।

ऐसा लगता है कि मानक और इलिप्सिस रूपांतरण अनुक्रमों के लिए प्रतिबंध केवल उन मामलों में जोड़ा गया था जहां अन्य उपयोगकर्ता परिभाषित रूपांतरण पहले से ही हो चुका है। या कम से कम मैं http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84 पढ़ता हूं।

कैसे मानक प्रतिलिपि आरंभीकरण के दूसरे चरण, एक अस्थायी जो पहले से ही सही प्रकार है से जो प्रतियां प्रतिबंध केवल लागू करने के लिए सावधान है यह दिलचस्प है (और था एक उपयोगकर्ता-निर्धारित रूपांतरण के माध्यम से संभावित रूप से प्राप्त!) । फिर भी सूची-आरंभीकरण के लिए, कोई समान तंत्र मौजूद है लगता है ...

+2

spec में दोष की तरह लगता है। इस तरह की रिपोर्ट करने के लिए सबसे अच्छा है। 'X {Y {} {Y {}}' X {Y {}} 'नहीं होने पर' एक्स {वाई {}, वाई {}} 'काम करने का कोई कारण नहीं है। –

+0

@ निकोलबोलस मैंने नीचे एक दोष रिपोर्ट तैयार की है: http://stackoverflow.com/a/12732730/567292 – ecatmur

4

13.3.3.1p4 के मूल उद्देश्य का वर्णन करने के लिए कैसे 12.3p4 कि में आवश्यकता लागू करने के लिए है:

4 - अधिक से अधिक एक उपयोगकर्ता द्वारा परिभाषित रूपांतरण (कन्स्ट्रक्टर या रूपांतरण फ़ंक्शन) को एक ही मान पर लागू किया जाता है।

defect 84, 13.3.3 से पहले।देख 13.3.1.4 [over.match; उपयोगकर्ता परिभाषित रूपांतरण द्वारा एक आरंभीकरण के संदर्भ में (यानी, जब कोई उपयोगकर्ता-निर्धारित रूपांतरण समारोह के तर्क पर विचार -

4: 1p4 लगभग विशुद्ध रूप से जानकारीपूर्ण गया था .copy], 13.3.1.5 [over.match.conv]), केवल मानक रूपांतरण अनुक्रम और इलिप्सिस रूपांतरण अनुक्रमों की अनुमति है।

इसका कारण यह है 13.3.1.4 अनुच्छेद 1 गोली 2 और 13.3.1.5p1b1 वर्ग S उपज प्रकार T, जहां S प्रारंभकर्ता अभिव्यक्ति की कक्षा के प्रकार और T है पर उन लोगों के लिए उम्मीदवार कार्यों को प्रतिबंधित के प्रकार है ऑब्जेक्ट प्रारंभ किया जा रहा है, इसलिए किसी अन्य उपयोगकर्ता द्वारा परिभाषित रूपांतरण रूपांतरण अनुक्रम को सम्मिलित करने के लिए कोई अक्षांश नहीं है। (13.3.1.4p1b1 एक और मामला है; नीचे देखें)।

दोष 84 वर्ग कॉपी-आरंभीकरण के दूसरे चरण में निर्माता के एकल पैरामीटर (यहाँ के निर्माता के लिए स्वीकार्य रूपांतरण दृश्यों सीमित करके auto_ptr बचाव की मरम्मत (यानी auto_ptr<Derived> -> auto_ptr<Base> -> auto_ptr_ref<Base> -> auto_ptr<Base>, दो रूपांतरण कार्यों और एक परिवर्तित निर्माता के माध्यम से) auto_ptr<Base>auto_ptr_ref<Base> लेने, एक रूपांतरण समारोह के उपयोग की अनुमति न देने auto_ptr<Base> से अपने तर्क) कन्वर्ट करने के लिए:

4 - हालांकि, जब कोई उपयोगकर्ता-निर्धारित रूपांतरण समारोह के तर्क 13.3.1.3 [से अधिक की एक उम्मीदवार है कि विचार .match.ctor] जब दूसरे चरण में अस्थायी की प्रतिलिपि बनाने के लिए आह्वान किया गया ओ एफए वर्ग प्रति-प्रारंभिकरण, या 13.3.1.4 [over.match.copy], 13.3.1.5 [over.match.conv], या 13.3.1.6 [over.match.ref] सभी मामलों में, केवल मानक रूपांतरण अनुक्रम और इलिप्सिस रूपांतरण अनुक्रमों की अनुमति है।

n2672 तो कहते हैं:

[...] 13.3.1.7 द्वारा [over.match.list] जब एक ही तर्क या के रूप में प्रारंभकर्ता सूची गुजर जब प्रारंभकर्ता सूची ठीक एक तत्व है और कुछ दसवीं कक्षा या (संभवतः सीवी-योग्य) एक्स एक्स के एक निर्माता के पहले पैरामीटर के लिए माना जाता है, [...]

यह स्पष्ट रूप से उलझन में है, के रूप में केवल रूपांतरण के संदर्भ में रूपांतरण है कि 13.3.1.3 और 13.3.1.7 तक उम्मीदवार हैं, कन्स्ट्रक्टर हैं, रूपांतरण मज़ेदार नहीं हैं ctions। Defect 978 इस को सही:

4 - हालांकि, जब एक निर्माता या उपयोगकर्ता-निर्धारित रूपांतरण समारोह के तर्क [...]

पर विचार यह भी 13.3.1.4p1b1 12.3p4 के अनुरूप बना देता है, के रूप में यह अन्यथा कॉपी-प्रारंभ में कंस्ट्रक्टर्स परिवर्तित करने की असीमित आवेदन की अनुमति होगी:

struct S { S(int); }; 
struct T { T(S); }; 
void f(T); 
f(0); // copy-construct T by (convert int to S); error by 12.3p4 

मुद्दा तो क्या भाषा 13.3.1.7 साधन की चर्चा करते हुए है। X की प्रतिलिपि बनाई जा रही है या स्थानांतरित किया जा रहा है, इसलिए भाषा X तर्क पर पहुंचने के लिए उपयोगकर्ता द्वारा परिभाषित रूपांतरण लागू करने को छोड़ रही है।std::initializer_list में कोई रूपांतरण फ़ंक्शन नहीं है, इसलिए भाषा को किसी और चीज़ पर लागू करने का इरादा होना चाहिए; अगर यह रूपांतरण कार्यों को बाहर करने का इरादा नहीं है, यह कंस्ट्रक्टर्स परिवर्तित नहीं होनी चाहिए:

struct R {}; 
struct S { S(R); }; 
struct T { T(const T &); T(S); }; 
void f(T); 
void g(R r) { 
    f({r}); 
} 

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

struct U { U(std::initializer_list<int>); }; 
struct V { V(const V &); V(U); }; 
void h(V); 
h({{1, 2, 3}}); 

संपादित करें: और जो कुछ के माध्यम से चला, मैं a discussionJohannes Schaub से पाया है कि इस विश्लेषण की पुष्टि करता है:

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


ठीक है, बंद एक दोष रिपोर्ट देने के लिए। मैं 13.3.3.1p4 अप बंटवारे का प्रस्ताव करने के लिए जा रहा हूँ:

4 - हालांकि, जब एक निर्माता या उपयोगकर्ता-निर्धारित रूपांतरण समारोह एक उम्मीदवार है कि के तर्क पर विचार: 13.3 द्वारा

  • । 1.3 [over.match.ctor] जब कक्षा प्रति-प्रारंभिकरण के दूसरे चरण में अस्थायी की प्रतिलिपि बनाने के लिए, या
  • 13.3.1.4 [over.match.copy], 13.3.1.5 [over.match द्वारा .conv], या 13.3.1.6 [over.match.ref] सभी मामलों में,

केवल मानक रूपांतरण अनुक्रम और इलिप्सिस रूपांतरण अनुक्रमों पर विचार किया जाता है; एक वर्ग X के एक निर्माता के पहले तर्क पर विचार करते समय 13.3.1.7 [over.match.list] द्वारा उम्मीदवार है जब प्रारंभिक सूची को एक तर्क के रूप में पास करते हैं या जब प्रारंभकर्ता सूची में एक तत्व होता है, तो उपयोगकर्ता द्वारा परिभाषित किया गया है X में रूपांतरण या संदर्भ (संभवतः सीवी -क्वालिफाइड) X केवल तभी माना जाता है जब इसका उपयोगकर्ता परिभाषित रूपांतरण रूपांतरण फ़ंक्शन द्वारा निर्दिष्ट किया गया हो। [नोट: क्योंकि सूची-प्रारंभिकरण के संदर्भ में एक अंतर्निहित रूपांतरण अनुक्रम में एक से अधिक उपयोगकर्ता परिभाषित रूपांतरण की अनुमति है, यह प्रतिबंध सुनिश्चित करने के लिए आवश्यक है कि X का कनवर्ट करने वाला कन्स्ट्रक्टर, जिसे एक एकल तर्क a कहा जाता है X या X से प्राप्त प्रकार का प्रकार X के कन्स्ट्रक्टर के खिलाफ संदिग्ध नहीं है, जिसे अस्थायी X ऑब्जेक्ट स्वयं a से बनाया गया है। - अंत नोट]

+0

मुझे पसंद है कि आप अभी भी रूपांतरण कार्यों की अनुमति कैसे देते हैं। यह 'संरचना ए {ए (int) बनाता है; }; संरचना बी {ऑपरेटर ए(); ऑपरेटर int(); }; बी बी; 'ए (int)' ctor (जैसे वर्तमान में यह करता है) चुनने के बजाय एक {बी}; अस्पष्ट। वर्तमान व्यवहार आश्चर्यजनक लगता है। –

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