2015-06-15 9 views
7

मैं उचित सदस्य फ़ंक्शन का उपयोग कर जेनेरिक वेक्टर ऑब्जेक्ट को कॉल करने के लिए this answer की शैली में SFINAE का उपयोग कर रहा हूं। उदाहरण के लिए, निम्न कोड operator[](int) const कॉल पहले, और अगर है कि तब operator()(int) const मौजूद नहीं है: के रूप में this thread में सुझाव दियासी ++ एसएफआईएनएई केवल एक वर्ग टेम्पलेट पैरामीटर के साथ क्यों विफल रहता है?

template<int I> struct rank : rank<I-1> { static_assert(I > 0, ""); }; 
template<> struct rank<0> {}; 

template<typename VectorType> 
struct VectorWrapper 
{ 
    auto get(int i) const 
    { 
     return get(v, i, rank<5>()); 
    } 

    template<typename V, typename = std::enable_if_t<has_bracket_operator<const V>::value> > 
    auto get(V const& v, int i, rank<2>) const 
    { 
     return v[i]; 
    } 

    template<typename V, typename = std::enable_if_t<has_parenthesis_operator<const V>::value> > 
    auto get(V const& v, int i, rank<1>) const 
    { 
     return v(i); 
    } 

    VectorType v; 
}; 
has_bracket_operator और has_parenthesis_operator लक्षण की स्थापना के साथ

, पूरे संकलित करता है तथा seems to work

हालांकि, अधिभारित वर्ग टेम्पलेट्स में सदस्य वेक्टर को पास करने से पहले अनावश्यक लगता है, इसलिए मैंने इसे पास किए बिना इसे स्थापित करने का प्रयास किया। निम्न त्रुटि संदेश के साथ

template<typename = std::enable_if_t<has_bracket_operator<VectorType>::value> > 
    auto get(int i, rank<2>) const 
    { 
     return v[i]; 
    } 

    template<typename = std::enable_if_t<has_parenthesis_operator<VectorType>::value> > 
    auto get(int i, rank<1>) const 
    { 
     return v(i); 
    } 

हालांकि अब संकलन में विफल रहता है (जीसीसी 5.1.0 में): इस के लिए, मैं कक्षा टेम्पलेट स्थापित करने के लिए इस्तेमाल किया VectorType पैरामीटर के साथ टेम्पलेट पैरामीटर V प्रतिस्थापित

/usr/local/include/c++/5.1.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = has_parenthesis_operator<std::vector<int> >::value; _Tp = void]': 
main.cpp:46:10: required from 'struct VectorWrapper<std::vector<int> >' 
main.cpp:59:38: required from here 
/usr/local/include/c++/5.1.0/type_traits:2388:61: error: no type named 'type' in 'struct std::enable_if<false, void>' 
    using enable_if_t = typename enable_if<_Cond, _Tp>::type; 

DEMO

सवाल:

  • इस संकलन त्रुटि का कारण क्या है?
  • क्या मेरे पहले कोड ब्लॉक के अलावा कोई उचित कामकाज है? (यही वह है जो सामान्य कोडिंग शैली को बरकरार रखता है - जहां किसी को सदस्यों को पास नहीं करना पड़ता है)।

उत्तर

3

SFINAE [temp.deduct]/8 से, जोर मेरा हमें की बात आती है:

गलत प्रकार या अभिव्यक्ति में एक प्रतिस्थापन परिणाम, प्रकार कटौती में विफल रहता है। एक अमान्य प्रकार या अभिव्यक्ति है जो प्रतिस्थापित तर्कों का उपयोग करके लिखा गया है, निदान के साथ, बीमार हो जाएगा। [नोट: यदि कोई निदान की आवश्यकता नहीं है, तो कार्यक्रम अभी भी खराब है। प्रतिस्थापन प्रक्रिया के हिस्से के रूप में एक्सेस जांच की जाती है। -जेंड नोट] फ़ंक्शन प्रकार के तत्काल संदर्भ में केवल अमान्य प्रकार और अभिव्यक्तियां और इसके टेम्पलेट पैरामीटर प्रकारों में कटौती विफलता हो सकती है।

तत्काल संदर्भ टेम्पलेट घोषणा में क्या है।अपने प्रारंभिक उदाहरण में:

template<typename V, typename = std::enable_if_t<has_bracket_operator<const V>::value> > 
auto get(V const& v, int i, rank<2>) const 

V तत्काल संदर्भ में है, इसलिए enable_if पर एक प्रतिस्थापन विफलता सिर्फ एक कटौती विफलता है।

हालांकि, अपने दूसरे उदाहरण में:

template<typename = std::enable_if_t<has_bracket_operator<VectorType>::value> > 
auto get(int i, rank<2>) const 

VectorTypeget के तत्काल संदर्भ में नहीं है, इसलिए एक विफलता यहाँ एक कटौती विफलता नहीं होगा, यह एक कठिन त्रुटि होगा।

जब तक VectorType इन सभी ऑपरेटरों के पास होता है।

किसी भी टेम्पलेट समस्या का समाधान केवल अधिक टेम्पलेट जोड़ने के लिए है। इस मामले में, बल VectorType एक और प्रकार शुरू करने से तत्काल संदर्भ में होने चाहिए:

template<typename T=VectorType, typename = std::enable_if_t<has_bracket_operator<T>::value> > 
auto get(int i, rank<2>) const 

और get<>() कहते हैं।

+0

मुझे यकीन नहीं है कि "तत्काल संदर्भ" क्या प्रासंगिक है (हालांकि समाधान ध्वनि है)। यह [सीडब्ल्यूजी 1635] है (http://wg21.link/cwg1635)। –

+0

@ टी.सी. क्या इसका मतलब है कि संकलन करना सही नहीं है लेकिन संभवतः नहीं होना चाहिए, या यह संकलित होना चाहिए और संकलक त्रुटियों में हैं? – Barry

+0

मुझे नहीं पता कि सीडब्ल्यूजी उस मुद्दे के बारे में क्या करने जा रहा है। अभी मैं शायद इस underspecified कॉल करेंगे। –

4

अपने में नाकाम रहने के उदाहरण में, टेम्पलेट पैरामीटर VectorType पहले से ही समय मिलता द्वारा निर्धारित किया गया है हल किया जा रहा है। SFINAE कार्य करने के लिए, आपको उस विधि कॉल पर SFINAE संकल्प के लिए उपयोग किए जा रहे टेम्पलेट पैरामीटर बनाना होगा। निम्नलिखित की तरह आप चाहते हैं अपने पहले उदाहरण के संशोधन काम करने के लिए है करने के लिए:

template<int I> struct rank : rank<I-1> { static_assert(I > 0, ""); }; 
template<> struct rank<0> {}; 

template<typename VectorType> 
struct VectorWrapper 
{ 
    auto get(int i) const 
    { 
     return get(v, i, rank<5>()); 
    } 

    template<typename V=VectorType, typename = std::enable_if_t<has_bracket_operator<const V>::value> > 
    auto get(int i, rank<2>) const 
    { 
     return v[i]; 
    } 

    template<typename V=VectorType, typename = std::enable_if_t<has_parenthesis_operator<const V>::value> > 
    auto get(int i, rank<1>) const 
    { 
     return v(i); 
    } 

    VectorType v; 
}; 

इस तरह, V जब get कहा जाता है हल हो गई है, और इसे सही ढंग SFINAE का प्रयोग करेंगे।

+0

मैं परिवर्तन किया है। – JKor

3

या फिर आप टैग भेजने उपयोग कर सकते हैं:

auto get(int i) const 
{ 
    return get(i, has_bracket_operator<VectorType>(), has_parenthesis_operator<VectorType>()); 
} 

auto get(int i, std::true_type /*brackets*/, std::false_type /*parenthesis*/) const 
{ 
    return v[i]; 
} 

auto get(int i, std::false_type /*brackets*/, std::true_type /*parenthesis*/) const 
{ 
    return v(i); 
} 

demo

+1

मुझे लगता है कि अगर वेक्टर में ऑपरेटर() (int) 'नहीं है तो यह असफल हो जाएगा। – davidhigh

+0

आप ऐसा क्यों सोचते हैं? http://coliru.stacked-crooked.com/a/0a32631cc21deeb3। मुझे आपकी टिप्पणी समझ में नहीं आ रही है। वेक्टर में 'ऑपरेटर() (int) ' – grisha

+0

नहीं है क्योंकि मैंने सोचा होगा कि संकलक उन कार्यों को तत्काल करता है, भले ही पैरामीटर इसे पारित किए गए हों। और जब यह 'ऑपरेटर()' संस्करण को चालू करने का प्रयास करता है, तो यह विफल हो जाता है। मुझे लगता है कि अभिव्यक्ति SFINAE काम कर रही है: 'decltype (v (i))' बीमार गठित है, फ़ंक्शन संभवतः स्वचालित रूप से अक्षम हो जाता है (?)। – davidhigh

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