2015-02-02 12 views
6

मैं एक छोटे से विशेषता स्तरीय लागू करना चाहते हैं निर्धारित करने के लिए एक प्रकार operator() ठीक से अतिभारित है, ताकि मैं बहुत की तरह एक प्रकार क्वेरी कर सकते हैं:सी ++ 11: टेम्पलेट मानकों में SFINAE, जीसीसी बनाम बजना

FunctorCheck<F, void(int, char)>::value 

मूल रूप से, मुझे this question से इसे कार्यान्वित करने के बारे में एक विचार आया, लेकिन Cppcon lecture on TMP देखने के बाद, यह मेरे सामने आया कि इस समस्या को और अधिक सुन्दर तरीके से हल किया जा सकता है। यह क्या मैं के साथ आया है, और इस संकलित करता है तथा बजना 3.5.0 पर दोषरहित चलाता है:

template <typename ...> 
using void_t = void; 

template <typename Functor, typename ... Args> 
using FunctorReturn = decltype(declval<Functor>()(declval<Args>()...)); 

template <typename Functor, typename Signature, typename = void> 
struct FunctorCheck: public std::false_type 
{}; 

template <typename Functor, typename R, typename ... Args> 
struct FunctorCheck<Functor, R(Args...), 
    void_t<FunctorReturn<Functor, Args ...>> // SFINAE can kick in here 
> : public std::is_same<R, FunctorReturn<Functor, Args ...>>::type 
{}; 

आपने गौर किया हो सकता है, मैं टेम्पलेट में SFINAE फायदा उठाने के लिए प्रस्तावित सी ++ 17 void_t उपयोग कर रहा हूँ विशेषज्ञता के पैरामीटर। जब FunctorReturn को Functor प्राप्त होता है - जो कि तर्क-सूची के साथ असंगत है, void_t<FunctorReturn<Functor, Args ...>> खराब हो जाएगा, SFINAE किक करेगा और गैर-विशिष्ट संस्करण को तुरंत चालू किया जाएगा। यदि पूर्व अभिव्यक्ति अच्छी तरह से बनाई गई है, तो std::is_same हमारे पास एक मैच है या नहीं, यह निर्धारित करने के लिए रिटर्न-प्रकार की तुलना करता है।

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

(इसके अलावा, किसी को भी यह कैसे दृश्य स्टूडियो के हाल के संस्करणों पर कैसा व्यवहार करेंगे के बारे में कोई सुराग नहीं है?)

+0

वह उपयोग करने के लिए 'टेम्पलेट struct voider {का उपयोग कर type = शून्य;} मतलब; टेम्पलेट void_t = typename voider :: प्रकार; 'सादे 'void_t' –

+0

नाइस के बजाय' अच्छा! यदि आप इसे उत्तर के रूप में पोस्ट करते हैं, तो मैं स्वीकार करूंगा (यह मानता है कि यह काम करता है) :-) – JorenHeit

+0

'std :: is_same' गलत दिखता है - आप कनवर्ट करने के माध्यम से आवेषण करते हैं, आपको भी वापस आना चाहिए। 'std :: is_same {} || std :: is_convertible , R> {} 'मेरे लिए एक बेहतर परीक्षण होगा। – Yakk

उत्तर

6

यह CWG issue 1558 था। अनिर्दिष्ट भाग उपनाम टेम्पलेट में अप्रयुक्त तर्कों का उपचार था। जीसीसी < 5.0 में अप्रयुक्त तर्कों का परिणाम प्रतिस्थापन विफलता नहीं हो सकता है, इसलिए void_tfails to verify your functor call, और क्लास टेम्पलेट विशेषज्ञता को तुरंत चालू करने का प्रयास करता है, जिसके परिणामस्वरूप हार्ड त्रुटि होती है।

जीसीसी (< 5.0) का संभावित हल निम्नलिखित दिया गया है:

template <typename...> 
struct voider 
{ 
    using type = void; 
}; 

template <typename... Ts> 
using void_t = typename voider<Ts...>::type; 

DEMO

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