2012-01-09 9 views
45

निम्नलिखित कोड: जब जीसीसी के साथ संकलितemplace_back() समान प्रारंभिकरण का उपयोग क्यों नहीं करता है?

#include <vector> 

struct S 
{ 
    int x, y; 
}; 

int main() 
{ 
    std::vector<S> v; 
    v.emplace_back(0, 0); 
} 

देता है निम्न त्रुटियों:

In file included from c++/4.7.0/i686-pc-linux-gnu/bits/c++allocator.h:34:0, 
       from c++/4.7.0/bits/allocator.h:48, 
       from c++/4.7.0/vector:62, 
       from test.cpp:1: 
c++/4.7.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = S; _Args = {int, int}; _Tp = S]': 
c++/4.7.0/bits/alloc_traits.h:265:4: required from 'static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]' 
c++/4.7.0/bits/alloc_traits.h:402:4: required from 'static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>]' 
c++/4.7.0/bits/vector.tcc:97:6: required from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, int}; _Tp = S; _Alloc = std::allocator<S>]' 
test.cpp:11:24: required from here 
c++/4.7.0/ext/new_allocator.h:110:4: error: new initializer expression list treated as compound expression [-fpermissive] 
c++/4.7.0/ext/new_allocator.h:110:4: error: no matching function for call to 'S::S(int)' 
c++/4.7.0/ext/new_allocator.h:110:4: note: candidates are: 
test.cpp:3:8: note: S::S() 
test.cpp:3:8: note: candidate expects 0 arguments, 1 provided 
test.cpp:3:8: note: constexpr S::S(const S&) 
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'const S&' 
test.cpp:3:8: note: constexpr S::S(S&&) 
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'S&&' 

सुझाव है कि vector नियमित () निर्माता सिंटैक्स का उपयोग कर रहा है emplace_back() को तर्क से तत्व के निर्माण के लिए। उपरोक्त काम जैसे उदाहरण बनाने के लिए vector{} वर्दी-प्रारंभिक वाक्यविन्यास का उपयोग क्यों नहीं करता है?

ऐसा लगता है कि {} का उपयोग करके खोने के लिए कुछ भी नहीं है (यह एक होने पर कन्स्ट्रक्टर को कॉल करता है, लेकिन तब भी काम करता है जब कोई नहीं होता), और यह सी ++ की भावना में अधिक होगा 11 {} का उपयोग करने के लिए - सभी के बाद, वर्दी प्रारंभिकरण का पूरा बिंदु यह है कि इसका उपयोग समान रूप से किया जाता है - अर्थात, हर जगह - वस्तुओं को प्रारंभ करने के लिए।

उत्तर

42

ग्रेट दिमाग एक जैसे सोचते हैं; v)। मैंने एक दोष रिपोर्ट जमा की और इस विषय पर मानक में बदलाव का सुझाव दिया। Direct vs uniform initialization in std::allocator:

http://cplusplus.github.com/LWG/lwg-active.html#2089

इसके अलावा, ल्यूक डेंटन मुझे कठिनाई को समझने में मदद की।

जब EmplaceConstructible (23.2.1 [container.requirements.general]/13) आवश्यकता प्रारंभ करने में एक वस्तु प्रयोग किया जाता है, सीधे प्रारंभ होता है। एक कुल या को प्रारंभ करने के साथ एक std :: startizer_list कंस्ट्रक्टर का उपयोग करके प्रारंभिक प्रकार प्रारंभिक प्रकार और अस्थायी स्थानांतरित करने की आवश्यकता है। यह std :: allocator :: प्रत्यक्ष-प्रारंभिकरण का उपयोग करके निर्माण, सूची-प्रारंभिकरण (कभी-कभी "वर्दी प्रारंभिक" कहा जाता है) वाक्यविन्यास का परिणाम है।

फेरबदल std :: संभाजक :: उपयोग करने के लिए सूची-प्रारंभ होता है, अन्य बातों के अलावा, एसटीडी करने के लिए :: initializer_list निर्माता भार के प्राथमिकता देते निर्माण, एक unintuitive और unfixable तरह से वैध कोड तोड़ने - वहाँ होगा कोई emplace_back के लिए कन्स्ट्रक्टर का उपयोग करने के लिए std :: startizer_list द्वारा अनिवार्य रूप से बिना पुश_बैक को पुन: कार्यान्वित किया गया है।

std::vector<std::vector<int>> v; 
v.emplace_back(3, 4); // v[0] == {4, 4, 4}, not {3, 4} as in list-initialization 

प्रस्तावित समझौता std :: is_constructible, जो सीधे-प्रारंभ अच्छी तरह का गठन किया गया है या परीक्षण के साथ SFINAE उपयोग करने के लिए है। यदि is_constructible गलत है, तो वैकल्पिक std :: allocator :: निर्माण अधिभार चुना जाता है जो सूची-प्रारंभिकरण का उपयोग करता है। चूंकि सूची-प्रारंभिकरण हमेशा प्रत्यक्ष-प्रारंभिकरण पर वापस आ जाता है, इसलिए उपयोगकर्ता सूची-प्रारंभिकरण (वर्दी-प्रारंभिकरण) का उपयोग हमेशा डायग्नोस्टिक संदेशों को देखेगा, क्योंकि प्रत्यक्ष-प्रारंभिक अधिभार विफल नहीं हो सकता है।

मैं इस योजना में अंतराल का पर्दाफाश करने वाले दो कोने के मामलों को देख सकता हूं। एक होता है जब std :: initiizer_list के लिए किए गए तर्क कन्स्ट्रक्टर को संतुष्ट करते हैं, जैसे उदाहरण के ऊपर में {3, 4} के मान को सम्मिलित करने का प्रयास करना।वर्कअराउंड std :: startizer_list प्रकार को स्पष्ट रूप से निर्दिष्ट करना है, जैसा कि v.emplace_back (std ::itializer_list (3, 4)) में है। चूंकि यह से मेल खाता है जैसे कि std :: startizer_list को घटाया गया था, वहां कोई वास्तविक समस्या नहीं है।

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

+2

कोई भी सिंटैक्टिक ब्रेसिज़ इनिट सूचियों को पूरी तरह से आगे बढ़ाने के लिए एक भाषा supporrt प्रकार का आविष्कार कर सकता है। फिर कोई सिर्फ emplace_back ({a, b, ...}) –

+4

@ जोहान्सचैब-लिटब: IMHO कह सकता है, यह 'std :: startizer_list' जैसा होना चाहिए था। लेकिन 'std :: आवंटक' के लिए सरल संशोधन चीजों को ठीक से ठीक करना चाहिए। – Potatoswatter

+0

क्या होगा यदि theuser एक कस्टम आवंटन के साथ एक वेक्टर को प्रतिस्थापित करना चाहता है और emplace_back (1,2, alloc) लिखता है। इसे ({1,2}, आवंटन) के रूप में अग्रेषित करने के बारे में कैसे पता चलता है? आईएमओ कि आवंटक हैक चीज़ों ecen अधिक तोड़ता है। एक उचित समाधान पर काम किया जाना चाहिए। –