2012-11-22 25 views
21

के साथ नहीं, जीसीसी 4.7.2 और क्लैंग 3.1 दोनों के साथ कुछ सी ++ 11 कोड संकलित करते समय, मैं क्लैंग के साथ एक समस्या में भाग गया जहां टेम्पलेट तर्क को कम करने के लिए प्रबंधन नहीं किया गया था जीसीसी सफल एक और अधिक सार रूप में, कोड इस तरह दिखता है:टेम्पलेट पैरामीटर के रूप में वैराडिक टेम्पलेट: कटौती जीसीसी के साथ काम करता है लेकिन क्लैंग

src/test.cc:

struct Element { 
}; 

template <typename T> 
struct FirstContainer { 
}; 

template <typename T, typename U = Element> 
struct SecondContainer { 
}; 

template <template <typename> class Container> 
void processOrdinary(Container<Element> /*elements*/) { 
} 

template <template <typename, typename> class Container> 
void processOrdinary(Container<Element, Element> /*elements*/) { 
} 

template <template <typename, typename...> class Container> 
void processVariadic(Container<Element> /*elements*/) { 
} 

int main() { 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(SecondContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic<SecondContainer>(SecondContainer<Element>{}); 
    // This function instantiation works in GCC but not in Clang. 
    processVariadic(SecondContainer<Element>{}); 
    return 0; 
} 

मानक के §14.8.2 में §14.3.3 में उदाहरण और विशिष्टताओं को पढ़ने से मुझे लगता है कि कटौती काम करनी चाहिए, लेकिन मैं निश्चित रूप से नहीं कह सकता। यह मुझे उत्पादन से प्राप्त आउटपुट है:

mkdir -p build-gcc/ 
g++ -std=c++0x -W -Wall -Wextra -Weffc++ -pedantic -c -o build-gcc/test.o src/test.cc 
g++ -o build-gcc/test build-gcc/test.o 
mkdir -p build-clang/ 
clang++ -std=c++11 -Weverything -Wno-c++98-compat -c -o build-clang/test.o src/test.cc 
src/test.cc:34:3: error: no matching function for call to 'processVariadic' 
    processVariadic(SecondContainer<Element>{}); 
    ^~~~~~~~~~~~~~~ 
src/test.cc:21:6: note: candidate template ignored: failed template argument deduction 
void processVariadic(Container<Element> /*elements*/) { 
    ^
1 error generated. 
make: *** [build-clang/test.o] Fel 1 

परिणाम अलग क्यों हैं? क्या जीसीसी मैला, क्लैंग गूंगा है, क्या मेरे कोड में अनिर्दिष्ट व्यवहार या उनमें से सभी शामिल हैं?

+0

मैं आपसे सहमत हूं। सी ++ 11 अंतिम मसौदे में जो कुछ भी मैंने देखा है, वह इंगित करेगा कि यह काम करना चाहिए। 14.3.3.3 विशेष रूप से प्रासंगिक है। –

+0

आपके उदाहरण में 'typedef int Element; 'है, है ना? – Quuxplusone

+0

नहीं, कोड की शुरुआत में मैं एलिमेंट नाम के साथ एक संरचना को परिभाषित करता हूं। – psyill

उत्तर

7

बजना इस कॉल के लिए तर्क अनुमान करने की कोशिश कर रहा है:

processVariadic(SecondContainer<Element>{}); 

SecondContainer के बाद से एक डिफ़ॉल्ट टेम्पलेट तर्क है, इस के बराबर है:

processVariadic(SecondContainer<Element, Element>{}); 

इस प्रकार, यह के साथ टेम्पलेट तर्क कटौती करता है P = Container<Element> और A = SecondContainer<Element, Element>। यह तुरंत अनुमान लगा सकता है कि Container टेम्पलेट पैरामीटर SecondContainer है।

अगला, यह टेम्पलेट तर्कों को मानता है। चूंकि तर्क प्रकार पूरी तरह से हल हो गया है, क्लैंग का मानना ​​है कि पैरामीटर में कई प्रकार के होना चाहिए, या कटौती संभवतः सफल नहीं हो सकती है (यह डिफ़ॉल्ट तर्कों को खाते में नहीं लेती है)। तो यह एक कटौती विफलता झंडे।


तो, क्या होने वाला है? [temp.deduct.type]p8 के शब्दों में,

एक टेम्पलेट प्रकार तर्क T, एक टेम्पलेट टेम्पलेट तर्क TT या एक टेम्पलेट गैर प्रकार तर्क मैं अगर P और A निम्नलिखित रूपों में से एक है निष्कर्ष निकाला जा सकता है:
[...]
TT<T>
TT<i>
TT<>
जहां [...] <T> टेम्पलेट तर्क सूचियों जहां कम से कम एक आर्ग का प्रतिनिधित्व करता है स्मारक में T, <i> टेम्पलेट तर्क सूचियों का प्रतिनिधित्व करता है जहां कम से कम एक तर्क में i और <> टेम्पलेट तर्क सूचियों का प्रतिनिधित्व करता है जहां कोई तर्क T या i नहीं है।

आदेश टेम्पलेट तर्क से मेल करने के लिए, हम [temp.deduct.type]p9 की ओर रुख:

P तो एक रूप है कि <T> या <i> होता है, तो संबंधित टेम्पलेट तर्क सूची P से प्रत्येक तर्क Pi के साथ तुलना में किया जाता है A की संबंधित टेम्पलेट तर्क सूची के संबंधित तर्क Ai

यहां देखने के लिए दो चीज़ें हैं। एक यह है कि यह नियम यह नहीं कहता कि क्या होता है यदि सूची Pi और Ai अलग-अलग लंबाई (जैसे वे इस मामले में हैं) हैं, और आम व्याख्या यह प्रतीत होती है कि बेमेल आइटम की जांच नहीं की जाती है। दूसरा यह है कि इस नियम का पालन नहीं किया जाना चाहिए, क्योंकि P के रूप में <T> या <i> नहीं है (इसमें केवल <> है, क्योंकि इसमें कोई टेम्पलेट पैरामीटर नहीं है)।


तो, क्लैंग इस कोड को अस्वीकार करने में गलत था। मैंने इसे r169475 में ठीक कर दिया है।