2016-12-14 9 views
16
#include <type_traits> 

template <typename T> 
struct C; 

template<typename T1, typename T2> 
using first = T1; 

template <typename T> 
struct C<first<T, std::enable_if_t<std::is_same<T, int>::value>>> 
{ 
}; 

int main() 
{ 
} 

विभिन्न compilers द्वारा संकलन के परिणाम:क्या निम्नलिखित कोड C++ मानक के अनुसार संकलित करना चाहिए?

MSVC:

error C2753: 'C': partial specialization cannot match argument list for primary template

जीसीसी-4.9:

error: partial specialization 'C' does not specialize any template arguments

बजना सभी संस्करणों:

error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

जी cc-5 +: सफलतापूर्वक

संकलित और additionaly मैं करते रहे कि तुच्छ विशेषज्ञता की तरह हैं:

template<typename T> 
struct C<T> 
{ 
}; 

सफलतापूर्वक जीसीसी द्वारा संकलित की विफल रहता है। तो ऐसा लगता है जैसे यह पता चलता है कि मेरे मूल उदाहरण में विशेषज्ञता गैर-तुच्छ है। तो मेरा सवाल यह है - इस तरह के पैटर्न को सी ++ मानक द्वारा स्पष्ट रूप से वर्जित किया गया है या नहीं?

+7

मैं चाहता हूं कि मैंने कभी यह लिखा नहीं [यह बात] (http://stackoverflow.com/a/31213703/2756719)। सवाल यह है कि [क्या आंशिक विशेषज्ञता प्राथमिक टेम्पलेट की तुलना में अधिक विशिष्ट है] (https://timsong-cpp.github.io/cppwp/temp.class.spec#8.2), जो उन्हें तुलना करके निर्धारित किया जाता है [पुनः लिखने के बाद दो फ़ंक्शन टेम्पलेट्स तक) (https://timsong-cpp.github.io/cppwp/temp.class.order)। दुर्भाग्यवश, [यह भी स्पष्ट नहीं है कि दो फ़ंक्शन टेम्पलेट घोषणाओं को फिर से लिखने के बाद एक ही फ़ंक्शन टेम्पलेट घोषित करें या नहीं] (https://wg21.link/cwg1980)। –

+2

@ टी.सी. मैं लिखने के दौरान था कि कटौती में 'पी' में गैर-कटौती वाली घटनाओं में तर्कों के प्रतिस्थापन को शामिल किया गया है (इसलिए दूसरा टेम्पलेट अधिक विशिष्ट है क्योंकि अद्वितीय संश्लेषित प्रकार 'is_same' के आंशिक विशेषज्ञता को ट्रिगर करने में विफल रहेगा), लेकिन मैं मुझे यकीन नहीं है कि कहीं भी शब्द में स्पष्ट है, न ही यह वास्तव में किस हद तक लागू होता है। – Columbo

+0

@ कोल्मुबो [temp.deduct.type]/1 का अंत ("जो पी को बना देगा, कट किए गए मूल्यों के प्रतिस्थापन के बाद (इसे घटाए गए ए को कॉल करें)"), की तरह? लेकिन मुझे लगता है कि यह किसी भी घटना में इस प्रतिस्थापन को संभालने के लिए सबसे अच्छा नहीं है। क्या होगा यदि विशेषता 'टेम्पलेट संरचना is_not_int: true_type {} है; टेम्पलेट <> struct is_not_int : false_type {}; '? एक सख्त पढ़ने का कहना है कि आंशिक विशेषज्ञता तब अमान्य है, लेकिन ऐसा लगता है ... सबसे अच्छा विचित्र। –

उत्तर

1

मुझे लगता है कि आप अपने कोड को सरल बना सकते हैं - इसमें type_traits के साथ कुछ लेना देना नहीं है। आप एक निम्नलिखित के साथ एक ही परिणाम प्राप्त करेंगे: ऑनलाइन संकलक में

template <typename T> 
struct C; 

template<typename T> 
using first = T; 

template <typename T> 
struct C<first<T>> // OK only in 5.1 
{ 
}; 

int main() 
{ 
} 

चेक (5.1 के तहत संकलित लेकिन 5.2 या 4.9 के साथ नहीं है, तो यह शायद एक बग है) - https://godbolt.org/g/iVCbdm

मुझे लगता है कि पूर्णांक जीसीसी 5 वे टेम्पलेट कार्यक्षमता के चारों ओर चले गए और एक ही प्रकार के दो विशेषज्ञ बनाने के लिए भी संभव है। जब तक आप इसका उपयोग करने की कोशिश नहीं करेंगे तब तक यह संकलित होगा।

template <typename T> 
struct C; 

template<typename T1, typename T2> 
using first = T1; 

template<typename T1, typename T2> 
using second = T2; 

template <typename T> 
struct C<first<T, T>> // OK on 5.1+ 
{ 
}; 

template <typename T> 
struct C<second<T, T>> // OK on 5.1+ 
{ 
}; 

int main() 
{ 
    C<first<int, int>> dummy; // error: ambiguous template instantiation for 'struct C<int>' 
} 

https://godbolt.org/g/6oNGDP

यह किसी भी तरह सी ++ 14 चर टेम्पलेट्स के लिए जोड़ा समर्थन से संबंधित हो सकता है। https://isocpp.org/files/papers/N3651.pdf

+0

ऐसा लगता है कि 5.1 में आपका उदाहरण काम करता है लेकिन 5.2 से शुरू होता है, यह "त्रुटि: आंशिक विशेषज्ञता 'संरचना सी ' किसी भी टेम्पलेट तर्कों का विशेषज्ञ नहीं है" के साथ एक छोटे टेम्पलेट उपनाम के साथ संकलित करने में विफल रहता है। इसलिए जीसीसी इस संबंध में विकसित हो रहा है :) – Predelnik

+0

शायद यह बग __N3651__ से __GCC 5.1__ और आंशिक रूप से __5.2__ में तय किया गया है। आंशिक रूप से क्योंकि दूसरा उदाहरण __5.2 को 6.2__ तक संकलित करेगा (आगे परीक्षण नहीं किया गया था)। ध्यान दें कि मैंने दूसरा, डमी टेम्पलेट प्रकार जोड़कर दूसरा उदाहरण संपादित किया है। मुझे यकीन नहीं है कि यह वास्तव में एक बग या एक विशेषता है। मेरी समझ में यह __int__ के लिए __int__ C__ के लिए दो बार विशेषज्ञ होगा। फ़ंक्शन के मामले में यह समस्या होगी क्योंकि आप अलग संकलन इकाई में फ़ंक्शन को विशेषज्ञ बना सकते हैं और इसके साथ लिंक कर सकते हैं - आपको कई परिभाषाएं मिलेंगी। वर्ग/संरचना के मामले में यह थोड़ा और जटिल है। –

+0

वैसे भी, यदि कंपाइलर आपको टेम्पलेट क्लास के लिए कई विशेषज्ञताओं को परिभाषित करने देता है, तो वे कैसे तय कर सकते हैं कि एक से एक? हम नहीं कर सकते –

4

महत्वपूर्ण अनुच्छेद [temp.class.spec]/(8.2) है, जिसके लिए आंशिक विशेषज्ञता प्राथमिक टेम्पलेट की तुलना में अधिक विशिष्ट होने की आवश्यकता है। क्लैंग वास्तव में शिकायत करता है कि तर्क सूची प्राथमिक टेम्पलेट के समान है: इसे [temp.class.spec]/(8.3) से issue 2033 (जिसे कहा गया है कि आवश्यकता अनावश्यक थी) को हटा दिया गया है, इसलिए अभी तक क्लैंग में लागू नहीं किया गया है। हालांकि, यह स्पष्ट रूप से जीसीसी में लागू किया गया है, यह देखते हुए कि यह आपके स्निपेट को स्वीकार करता है; यह और भी compiles the following, शायद इसी कारण से इसे अपने कोड संकलित (यह भी केवल संस्करण 5 के बाद से काम करता है):

template <typename T> 
void f(C<T>) {} 

template <typename T> 
void f(C<first<T, std::enable_if_t<std::is_same<T, int>::value>>>) {} 

अर्थात यह स्वीकार करता है कि घोषणाएं अलग हैं, इसलिए 1980 जारी करने के कुछ संकल्प को लागू करना होगा। यह नहीं लगता कि दूसरा अधिभार अधिक विशिष्ट है (वंडबॉक्स लिंक देखें), हालांकि, जो असंगत है, क्योंकि इसे उपरोक्त बाधा के अनुसार आपके कोड का निदान करना चाहिए (8.2)।

तर्कसंगत रूप से, वर्तमान शब्द आपके उदाहरण के आंशिक क्रम कार्य को वांछित और डैगर के रूप में बनाता है;: [temp.deduct.type]/1 कहा गया है कि [temp.alias]/3 के माध्यम से प्रकार से कटौती,

Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values […] that will make P , after substitution of the deduced values (call it the deduced A), compatible with A .

अब में, इस के बाद से मतलब यह होगा कि आंशिक आदेश कदम है, जिसमें आंशिक विशेषज्ञता के समारोह टेम्पलेट पैरामीटर टेम्पलेट है के दौरान, is_same में प्रतिस्थापन झूठी पैदावार (सामान्य पुस्तकालय कार्यान्वयन केवल आंशिक विशेषज्ञता का उपयोग करते हैं जो असफल होना चाहिए), और enable_if विफल रहता है। और डैगर; लेकिन यह अर्थशास्त्र सामान्य मामले में संतोषजनक नहीं है, क्योंकि हम ऐसी स्थिति का निर्माण कर सकते हैं जो आम तौर पर सफल हो, इसलिए एक अद्वितीय संश्लेषित प्रकार इसे पूरा करता है, और कटौती दोनों तरीकों से सफल होती है।

संभावित रूप से, सबसे सरल और सबसे मजबूत समाधान आंशिक क्रम के दौरान त्याग किए गए तर्कों को अनदेखा करना है (आपका उदाहरण खराब बना हुआ है)। एक भी इस मामले में कार्यान्वयन 'व्यवहार के प्रति अपने-बोध कर सकते हैं (अनुरूप 1157 जारी करने के लिए):

template <typename...> struct C {}; 

template <typename T> 
void f(C<T, int>) = delete; 

template <typename T> 
void f(C<T, std::enable_if_t<sizeof(T) == sizeof(int), int>>) {} 

int main() {f<int>({});} 

दोनों Clang और GCC नष्ट कर दिया फ़ंक्शन कॉल, यानी के रूप में इस का निदान का मानना ​​है कि पहले अधिभार अन्य की तुलना में अधिक विशिष्ट है । # 2 की महत्वपूर्ण संपत्ति यह प्रतीत होती है कि दूसरा टेम्पलेट तर्क अभी भी निर्भर है T पूरी तरह से गैर-अनुमानित संदर्भों में दिखाई देता है (यदि हम int से T को # 1 में बदलते हैं, तो कुछ भी नहीं बदलता है)। तो हम टाई ब्रेकर के रूप में छोड़े गए (और निर्भर?) टेम्पलेट तर्कों के अस्तित्व का उपयोग कर सकते हैं: इस तरह हमें संश्लेषित मूल्यों की प्रकृति के बारे में तर्क नहीं करना है, जो स्थिति है, और आपके मामले में उचित व्यवहार भी प्राप्त करें , जो अच्छी तरह से गठित किया जाएगा।


और डैगर; @ टी.सी. उल्लेख किया है कि [temp.class.order] के माध्यम से उत्पन्न टेम्पलेट्स को वर्तमान में एक गुणा घोषित इकाई — के रूप में व्याख्या किया जाएगा, समस्या 1980 देखें। यह इस मामले में मानक लोगों के लिए सीधे प्रासंगिक नहीं है, क्योंकि शब्द कभी भी उल्लेख नहीं करता है कि इन फ़ंक्शन टेम्पलेट्स घोषित किए गए हैं, उसी कार्यक्रम में अकेले रहने दें; यह सिर्फ उन्हें निर्दिष्ट करता है और फिर फ़ंक्शन टेम्पलेट्स की प्रक्रिया पर वापस आ जाता है।

और डैगर; यह पूरी तरह स्पष्ट नहीं है कि इस विश्लेषण को करने के लिए गहराई से कार्यान्वयन की आवश्यकता है। समस्या 1157 दर्शाती है कि "सही तरीके से" यह निर्धारित करने के लिए कि किस स्तर का विवरण आवश्यक है, एक टेम्पलेट का डोमेन दूसरे का उचित सबसेट है या नहीं। यह न तो व्यावहारिक होने के लिए आंशिक क्रम को लागू करने के लिए न तो व्यावहारिक और न ही उचित है। हालांकि, फुटनोट सेक्शन सिर्फ यह दिखाने के लिए चला जाता है कि यह विषय अनिवार्य रूप से अनिर्दिष्ट नहीं है, बल्कि दोषपूर्ण है।

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