2012-12-09 11 views
8

मैं एक साधारण वेक्टर वर्ग लिख रहा हूं और मैं कुछ सदस्य कार्य करना चाहता हूं जो केवल कुछ लंबाई के वैक्टर में उपलब्ध हैं (क्रॉस उत्पाद उदाहरण के लिए एक 3 तत्व वेक्टर)। मैं std :: enable_if भर में ठोकर खा रहा हूं और ऐसा लगता है कि यह वही कर सकता है जो मैं चाहता हूं, लेकिन मुझे लगता है कि यह सही तरीके से काम नहीं कर पा रहा है।सी ++ 11 std :: enable_if का उपयोग करके सदस्य कार्य को सक्षम करने के लिए वेक्टर विशिष्ट लंबाई

#include <iostream> 
#include <type_traits> 

template<typename T, unsigned int L> 
class Vector 
{ 
    private: 
     T data[L]; 

    public: 
     Vector<T,L>(void) 
     { 
      for(unsigned int i = 0; i < L; i++) 
      { 
       data[i] = 0; 
      } 
     } 

     T operator()(const unsigned int i) const 
     { 
      return data[i]; 
     } 

     T& operator()(const unsigned int i) 
     { 
      return data[i]; 
     } 

     Vector<typename std::enable_if<L==3, T>::type, L> cross(const Vector<T,L>& vec2) const 
     { 
      Vector<T,L> result; 

      result(0) = (*this)(1) * vec2(2) - (*this)(2) * vec2(1); 
      result(1) = (*this)(2) * vec2(0) - (*this)(0) * vec2(2); 
      result(2) = (*this)(0) * vec2(1) - (*this)(1) * vec2(0); 

      return result; 
     } 
}; 

int main(void) 
{ 
    Vector<double,3> v1; 
    Vector<double,3> v2; 
    Vector<double,3> v3; 
    //Vector<double,4> v4; 

    v1(0) = 1; 
    v1(1) = 2; 
    v1(2) = 3; 

    v2(0) = 4; 
    v2(1) = 5; 
    v2(2) = 6; 

    v3 = v1.cross(v2); 

    std::cout << v3(0) << std::endl; 
    std::cout << v3(1) << std::endl; 
    std::cout << v3(2) << std::endl; 

    return 0; 
} 

compiles ऊपर कोड और सही ढंग से चलता है, लेकिन अगर मैं Vector<double,4> v4 की घोषणा मैं करने के संकलन में निम्न त्रुटि uncomment:

vec.cpp: In instantiation of ‘class Vector<double, 4u>’: 
vec.cpp:46:22: required from here 
vec.cpp:29:59: error: no type named ‘type’ in ‘struct std::enable_if<false, double>’ 

किसी का कहना है करने में सक्षम है, जहां मैं गलत जा रहा हूँ है?

+0

की [? मैं बढ़ावा :: एक सदस्य समारोह पर \ _if सक्षम उपयोग कर सकते हैं] संभव डुप्लिकेट (http (यह अभी भी सी ++ मानक के उपर्युक्त दो पैराग्राफ से इस प्रकार है) .com/प्रश्न/4880 9 22/कैन-ए-यूज-बूस्टेनेबल-अगर-ऑन-ए-सदस्य-फ़ंक्शन) –

+1

आप शायद 'टाइपनाम std :: enable_if <एल == 3, वेक्टर > :: टाइप' के बजाय 'वेक्टर <टाइपनाम std :: enable_if :: प्रकार, एल>'। –

+1

(आप संभवतः 'टी कॉन्स्ट' ('' को वापस करने के लिए अपना कॉन्स 'ऑपरेटर() 'चाहते हैं। वर्तमान कोड ग्राहकों को' वेक्टर वी; वेक्टर कॉन्स और const_v = v; const_v (2) = 42.0; // नोट की तरह कुछ करने देता है 42 का लेखन एक अस्थायी होता है। उपयोगकर्ता द्वारा अपेक्षित नहीं ') –

उत्तर

8
template<unsigned LL = L> 
    Vector<typename std::enable_if<LL==3 && L == 3, T>::type, LL> 
    cross(const Vector<T,LL>& vec2) const 
    { 
    Vector<T,L> result; 

    result(0) = (*this)(1) * vec2(2) - (*this)(2) * vec2(1); 
    result(1) = (*this)(2) * vec2(0) - (*this)(0) * vec2(2); 
    result(2) = (*this)(0) * vec2(1) - (*this)(1) * vec2(0); 

    return result; 
    } 

पीएस। यह इस तरह क्यों काम करता है?

चर v4 वर्ग टेम्पलेट Vector है, जिसकी वजह से एक अंतर्निहित इन्स्टेन्शियशन का कारण बनता है, बारी में, वर्ग के सदस्य कार्यों की घोषणाओं के अंतर्निहित इन्स्टेन्शियशन, अन्य बातों के अलावा की परिभाषा (14.7.1 अंतर्निहित इन्स्टेन्शियशन [temp.inst] # 1)। यह बाद का तात्कालिकता, निश्चित रूप से, एक त्रुटि में परिणाम।

हम बजाय सदस्य समारोह बदल इस बिंदु सदस्य स्वयं टेम्पलेट को instantiated है पर एक ही खंड के अनुसार, एक सदस्य टेम्पलेट होने के लिए, और इस इन्स्टेन्शियशन लग रहा है, और अधिक या कम, की तरह हैं:

template<unsigned LL = 3> 
Vector<typename std::enable_if<LL==3 && 3 == 3, double>::type, LL> 
cross(const Vector<double,LL>& vec2) const; 

जो एक पूरी तरह से वैध टेम्पलेट घोषणा है। हम इस बिंदु पर कोई और तत्काल निष्पादन नहीं करते (और हम नहीं कर सकते)।

हालांकि, जब हम वास्तव में cross पर कॉल करने का प्रयास करते हैं, तो यह संदेह नहीं है, "एक संदर्भ जिसके लिए सदस्य/फ़ंक्शन परिभाषा मौजूद है" (14.7.1 लागू तत्काल [temp.inst] # 2 , # 3), cross टेम्पलेट (दूसरा cross टेम्पलेट, जो बाहरी वर्ग टेम्पलेट तत्कालता का परिणाम है) को तत्काल तत्काल माना जाता है और std::enable_if को अपना काम करने का मौका दिया जाता है। एक साइड नोट के रूप में, यह स्थिति है, जहां SFINAE सिद्धांत लागू है।

पीपीएस। कुछ और विस्तार करने के लिए, हालांकि ओपी प्रश्न से सीधे जुड़े नहीं हैं, लेकिन अभी भी उल्लेखनीय है कि समान परिस्थितियों को संभालने के लिए सदस्यों को टेम्पलेट्स के रूप में घोषित करना हमेशा आवश्यक नहीं होता है।

#include <type_traits> 

template<typename T> 
struct S 
{ 
    T x; 

    T foo() const { return x; } 

    typename std::remove_pointer<T>::type bar() const { return *x; } 
}; 

S<int> x; 
S<int *> y; 

जाहिर है, इन्स्टेन्शियशन S<int> में:

वहां स्थितियों में, जहां एक वर्ग टेम्पलेट का सदस्य नहीं "वैध" एक दिया इन्स्टेन्शियशन के लिए उदाहरण के लिए है, लेकिन अभी भी वर्ग टेम्पलेट instantiated जा सकता है, , अभिव्यक्ति *x अमान्य है, क्योंकि x का प्रकार int है। हालांकि, यह कार्यक्रम सही है। महत्वपूर्ण बात यह है कि अंतर्निहित तत्कालता के दौरान सदस्यों की घोषणाएं तत्काल हैं। उपर्युक्त मामले में, तत्काल S<int>घोषणाint bar() const; को तत्काल घोषित करने का कारण बनता है, जो पूरी तरह से सही घोषणा है।

बेशक

, अगर हमें बाद परिभाषा S<int>::bar की का दृष्टांत के लिए, की तरह का प्रयास:

void f() 
{ 
    x.foo(); 
    // x.bar(); // error 
    y.foo(); 
    y.bar(); 
} 

हम एक त्रुटि मिल जाएगा। // stackoverflow:

+0

धन्यवाद, हालांकि मुझे समझ में नहीं आता कि यह मेरे पास से अलग क्यों है। क्या यह सिर्फ इसलिए है क्योंकि व्यक्तिगत सदस्य कार्य को भी टेम्पलेट किया जाना चाहिए? – rozzy

+0

@ aero117, टेम्पलेट फ़ंक्शन के लिए कोई कोड उत्पन्न नहीं होता है जब तक कि यह तत्काल नहीं हो जाता है। आपके कोड में, कंपाइलर पूरे वर्ग के लिए कोड उत्पन्न करेगा (जब टेम्पलेट तत्काल हो), फ़ंक्शन समेत। लेकिन जब आप टेम्पलेट के रूप में फ़ंक्शन करते हैं, तो इस फ़ंक्शन के लिए कोड केवल तभी उत्पन्न होगा जब यह टेम्पलेट तत्काल हो, उदाहरण के लिए, फ़ंक्शन को कॉल करके। – soon

+0

पूर्ण-विशेष स्पष्टीकरण के लिए कुडोस! –

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