2015-09-11 18 views
10

के बीच प्रारंभकर्ता_सूची अंतर मैं समझने की कोशिश कर रहा हूं कि सी ++ 11 का सही व्यवहार प्रारंभिक सूचियों और const auto के संयोजन के दौरान होना चाहिए। मैं निम्नलिखित कोड के लिए जीसीसी और बजना के बीच अलग व्यवहार हो रही है और पता करने के लिए जो सही एक है चाहते हैं:कॉन्स ऑटो std :: क्लैंग और जीसीसी

#include <iostream> 
#include <typeinfo> 
#include <vector> 

int main() 
{ 
    const std::initializer_list<int> l1 = { 1, 2, 3 }; 
    const auto l2 = { 1, 2, 3 }; 

    std::cout << "explicit: " << typeid(l1).name() << std::endl; 
    std::cout << "auto:  " << typeid(l2).name() << std::endl; 
} 

जी के साथ ++ उत्पादन संकलित है:

explicit: St16initializer_listIiE 
auto:  St16initializer_listIKiE 

जबकि बजना ++ संकलित संस्करण पैदा करता है:

explicit: St16initializer_listIiE 
auto:  St16initializer_listIiE 

ऐसा नहीं है कि जीसीसी एक std::initializer_list<const int> में auto लाइन घूम रहा है, जबकि बजनापैदा करता है लगता है। जब मैं इसे std::vector प्रारंभ करने के लिए उपयोग करता हूं तो जीसीसी संस्करण समस्या उत्पन्न करता है। तो निम्नलिखित क्लैंग के तहत काम करता है लेकिन जीसीसी के लिए एक कंपाइलर त्रुटि उत्पन्न करता है।

// Compiles under clang but fails for GCC because l4 
std::vector<int> v2 { l2 }; 

जीसीसी सही संस्करण का निर्माण किया जाता है तो यह पता चलता है कि विभिन्न एसटीएल कंटेनर इन मामलों के लिए एक और सूची प्रारंभकर्ता अधिभार शामिल करने के लिए विस्तार किया जाना चाहिए लगता है।

नोट: यह व्यवहार जीसीसी (4.8, 4.9, 5.2) और क्लैंग (3.4 और 3.6) के कई संस्करणों में सुसंगत प्रतीत होता है।

+0

क्या आप 'std :: vector v2 (l2.begin(), l2.end()) देख सकते हैं; '(इसे काम करना चाहिए) इसे ध्यान में रखते हुए, शायद किसी भी प्रकार की प्रारंभिक सूची सूचियों को स्पष्ट रूप से परिवर्तित किया जाना चाहिए, यहां तक ​​कि अगर कटौती में परिवर्तन होता है। दूसरी तरफ, इसके परिणामस्वरूप प्रारंभकर्ता सूची कन्स्ट्रक्टर अन्य रचनाकारों को अक्सर छुपा सकता है। –

+0

हां 'std :: वेक्टर v2 (l2.begin(), l2.end()); वास्तव में काम करता है। – daveraja

उत्तर

6

जीसीसी बग। [Dcl.spec.auto]/p7 (N4527 के हवाले से):

एक चर का उपयोग कर एक प्लेसहोल्डर प्रकार आरंभ नहीं हो जाता, [...] निष्कर्ष निकाला वापसी प्रकार या वैरिएबल प्रकार प्रकार से निर्धारित किया जाता है की घोषणा की जब इसके प्रारंभिक के। [...] अन्यथा, T को वैरिएबल के घोषित प्रकार घोषित करें [...]। यदि प्लेसहोल्डर auto प्रकार-विनिर्देश है, तो प्रयुक्त प्रकार टेम्पलेट तर्क कटौती के नियमों का उपयोग करके निर्धारित किया जाता है। यदि प्रारंभिकरण प्रत्यक्ष-सूची-प्रारंभिकरण [...] है। [...] अन्यथा, PT से या तो एक नया आविष्कार प्रकार टेम्पलेट पैरामीटर U या, साथ auto की घटनाओं की जगह प्राप्त करता है, तो प्रारंभ कॉपी-सूची-प्रारंभ, std::initializer_list<U> के साथ है। UU के लिए फ़ंक्शन कॉल (14.8.2.1) से टेम्पलेट तर्क कटौती के नियमों का उपयोग करके मान को घटाएं, जहां P एक फ़ंक्शन टेम्पलेट पैरामीटर प्रकार है और संबंधित तर्क प्रारंभकर्ता है [...]। यदि कटौती विफल हो जाती है, तो घोषणा खराब हो जाती है। अन्यथा, वैरिएबल या रिटर्न प्रकार के लिए घटाया गया प्रतिस्थापित UP में प्रतिस्थापित करके प्राप्त किया जाता है।

इस प्रकार, const auto l2 = { 1, 2, 3 }; में, कटौती के रूप में समारोह टेम्पलेट

template<class U> void meow(const std::initializer_list<U>); 

कॉल meow({1, 2, 3}) दिया के लिए करता है, तो किया जाता है।

अब कॉन्स्ट-कम केस auto l3 = { 1, 2, 3 }; पर विचार करें (जो जीसीसी सही ढंग से std::initializer_list<int> के रूप में घटाता है)। इस मामले में कटौती के रूप में समारोह टेम्पलेट

template<class U> void purr(std::initializer_list<U>); 

कॉल purr({1, 2, 3}) दिया के लिए करता है, तो किया जाता है।

चूंकि फ़ंक्शन पैरामीटर के शीर्ष-स्तर की सीवी-योग्यता को अनदेखा किया जाता है, इसलिए यह स्पष्ट होना चाहिए कि दो कटौती एक ही प्रकार की होनी चाहिए।


[temp.deduct।फोन]/p1: जैसा कि नीचे वर्णित

खाका तर्क कटौती प्रत्येक कार्य टेम्पलेट पैरामीटर प्रकार की तुलना द्वारा किया जाता है कॉल के इसी तर्क के प्रकार के साथ (यह P कहते हैं) (यह A कहते हैं)। तो P, एक आश्रित प्रकार है P से संदर्भ और सीवी-क्वालिफायर को दूर करने देता है std::initializer_list<P'> [...] कुछ P' के लिए [...] और तर्क एक गैर खाली प्रारंभकर्ता सूची (8.5.4), तो है कटौती प्रारंभिक सूची के प्रत्येक तत्व के लिए किया जाता है, P' फ़ंक्शन टेम्पलेट पैरामीटर प्रकार और प्रारंभकर्ता तत्व को इसके तर्क के रूप में लेता है।

बात का अनुमान लगाना P' (जो U है) 1, 2, या 3 के खिलाफ, प्रकार int के सभी शाब्दिक, स्पष्ट रूप से int अर्जित करता है।

+2

मुझे नहीं पता कि * शीर्ष-स्तरीय सीवी-योग्यता * यहां समस्या पर है, समस्या 'प्रारंभकर्ता_सूची ' है और 'const प्रारंभकर्ता_सूची ' –

+0

'ऑटो l3 = {1, 2, 3};' जीसीसी में एक ही टेम्पलेट पैरामीटर ('const int') को कम नहीं करें? –

+0

सही 'ऑटो l3 = {1,2,3};' जीसीसी में 'कॉन्स्ट ऑटो एल 2 = {1,2,3};' के समान टेम्पलेट पैरामीटर को कम नहीं करता है। जब मैं इसे 'टाइपिड (एल 3) .name()' कोशिश करता हूं 'St16initializer_listIiE' बनाता है। – daveraja

4

एक जीसीसी बग रिपोर्ट wrong auto deduction from braced-init-list इस और इसी तरह के मामलों के बारे में नहीं है और रिचर्ड स्मिथ को इंगित करता है कि यह एक जीसीसी बग है:

भी सरल testcase:

#include <initializer_list> 
const auto r = { 1, 2, 3 }; 
using X = decltype(r); 
using X = const std::initializer_list<int>; 

विफल रहता है क्योंकि decltype(r)const std::initializer_list<const int> के रूप में निष्कर्ष निकाला है const std::initializer_list<int> के बजाए।

एक चर एक प्लेसहोल्डर प्रकार का उपयोग घोषित जब आरंभ नहीं हो जाता है, या एक वापसी कथन:

मसौदा सी की धारा ++ मानक खंड 7.1.6.4[dcl.spec.auto] जो कहते हैं हो सकता है फ़ंक्शन में एक रिटर्न प्रकार के साथ घोषित किया गया है जिसमें प्लेसहोल्डर प्रकार होता है, कट किए गए रिटर्न प्रकार या चर प्रकार को इसके प्रारंभकर्ता के प्रकार से निर्धारित किया जाता है। [...] टी को परिवर्तनीय या फ़ंक्शन के रिटर्न प्रकार का घोषित प्रकार होना चाहिए। यदि प्लेसहोल्डर ऑटो प्रकार-विनिर्देशक है, तो प्रयुक्त प्रकार टेम्पलेट तर्क कटौती के नियमों का उपयोग करके निर्धारित किया जाता है। [...] अन्यथा, नए आविष्कार प्रकार टेम्पलेट पैरामीटर यू के साथ ऑटो की घटनाओं को प्रतिस्थापित करके टी से पी प्राप्त करें या यदि प्रारंभकर्ता एक stced :: initizer_- सूची के साथ एक ब्रेसिड-इनिट-सूची है। फ़ंक्शन कॉल (14.8.2.1), से टेम्पलेट तर्क कटौती के नियमों का उपयोग करके यू के लिए मान घटाएं जहां पी एक फ़ंक्शन टेम्पलेट पैरामीटर प्रकार है और प्रारंभकर्ता संबंधित तर्क है [...] [उदाहरण:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int> 
auto x2 = { 1, 2.0 }; // error: cannot deduce element type 

अंत उदाहरण] [उदाहरण:

const auto &i = expr; 

मैं के प्रकार के कॉल च (expr) निम्नलिखित आविष्कार समारोह टेम्पलेट के में पैरामीटर यू के deduced प्रकार है :

template <class U> void f(const U& u); 

अंत उदाहरण]

+0

त्वरित प्रतिक्रिया और बग रिपोर्ट के लिंक के लिए धन्यवाद। – daveraja

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