2009-11-16 14 views
7

मैं वर्तमान की तरहसी ++ अंतर्निहित टेम्पलेट इन्स्टेन्शियशन

MatrixBase -> DenseMatrix 
      -> (other types of matrices) 
      -> MatrixView -> TransposeView 
         -> DiagonalView 
         -> (other specialized views of matrices) 

MatrixBase एक वर्ग पदानुक्रम है एक अमूर्त वर्ग जो इसको लागू करने के लिए मजबूर ऑपरेटर() (पूर्णांक, पूर्णांक) और इस तरह की चीजों को परिभाषित करने के लिए; यह संख्याओं के 2 आयामी सरणी का प्रतिनिधित्व करता है। MatrixView एक मैट्रिक्स को देखने की एक (संभावित रूप से परिवर्तनीय) तरीका का प्रतिनिधित्व करता है, जैसे इसे ट्रांसपोज़ करना या सबमिट्रिक्स लेना। MatrixView की बात कहने के लिए सक्षम होने के लिए है कुछ

तरह
Scale(Diagonal(A), 2.0) 

जहां Diagonal रिटर्न एक DiagonalView वस्तु जो हल्के अनुकूलक का एक प्रकार है।

अब प्रश्न (प्रश्न) है। मैं एक उदाहरण के रूप में एक बहुत ही सरल मैट्रिक्स ऑपरेशन का उपयोग करूंगा। मैं

template <class T> 
void Scale(MatrixBase<T> &A, const T &scale_factor); 

जैसे किसी फ़ंक्शन को परिभाषित करना चाहता हूं जो नाम स्पष्ट सुझाव देता है। मैं या तो ईमानदार-से-भलाई नॉन-व्यू मैट्रिक्स, या MatrixView के उप-वर्ग का उदाहरण प्राप्त करने में सक्षम होना चाहता हूं। ऊपर लिखा के रूप में इस तरह के प्रोटोटाइप

Scale(Diagonal(A), 2.0); 

के रूप में बयान के लिए काम नहीं करता है क्योंकि DiagonalView वस्तु Diagonal द्वारा लौटाए गए एक अस्थायी है, और Scale एक गैर स्थिरांक संदर्भ है, जो एक अस्थायी स्वीकार नहीं कर सकते लगता है। क्या यह काम करने का कोई तरीका है? मैंने SFINAE का उपयोग करने की कोशिश की, लेकिन मुझे यह सब ठीक नहीं समझ रहा है, और मुझे यकीन नहीं है कि इससे समस्या हल हो जाएगी। मेरे लिए यह महत्वपूर्ण है कि इन टेम्पलेट किए गए कार्यों को स्पष्ट टेम्पलेट तर्क सूची प्रदान किए बिना बुलाया जा सके (मुझे निहित तत्कालता चाहिए)। आदर्श रूप से ऊपर दिया गया बयान लिखित के रूप में काम कर सकता है।


संपादित करें: (अनुवर्ती प्रश्न)

के रूप में भारतीय स्टेट बैंक rvalue संदर्भ और temporaries के बारे में नीचे से जवाब दिया, वहाँ स्केल के दो संस्करणों को परिभाषित करने का कोई तरीका है, जिसके लिए एक गैर स्थिरांक rvalue संदर्भ लेता है गैर-विचार, और एक जो पास-दर-मूल्य दृश्य लेता है? समस्या इन दोनों के बीच संकलित समय पर अंतर करने के लिए है कि निहित तत्काल कार्य करेगा।


अद्यतन

मैं

ReadableMatrix 
WritableMatrix : public ReadableMatrix 
WritableMatrixView 
DenseMatrix : public WritableMatrix 
DiagonalView : public WritableMatrixView 

कारण WritableMatrixViewWritableMatrix से अलग है यह है कि दृश्य स्थिरांक संदर्भ द्वारा चारों ओर पास किया जाना चाहिए करने के लिए वर्ग पदानुक्रम बदल दिया है, जबकि मेट्रिसिस को स्वयं को गैर-कॉन्स रेफरी द्वारा पारित किया जाना चाहिए, इसलिए एक्सेसर सदस्य फ़ंक्शंस में अलग-अलग कॉन्स्टेस होते हैं। अब स्केल जैसे कार्यों के दो संस्करणों, एक स्थिरांक देखने के लिए, और वास्तविक मैट्रिक्स के लिए एक गैर स्थिरांक संस्करण देखते हैं कि के रूप में

template <class T> 
void Scale(const WritableMatrixView<T> &A, const T &scale_factor); 
template <class T> 
void Scale(WritableMatrix<T> &A, const T &scale_factor){ 
    Scale(WritableMatrixViewAdapter<T>(A), scale_factor); 
} 

नोट में परिभाषित किया जा सकता है। इसका मतलब Mult(A, B, C) जैसे कार्यों के लिए है, मुझे 8 ओवरलोड की आवश्यकता होगी, लेकिन कम से कम यह काम करता है। क्या काम नहीं करता है, हालांकि इन कार्यों का उपयोग अन्य कार्यों के भीतर कर रहा है।आप देखते हैं, प्रत्येक View -like वर्ग में सदस्य View है जो यह देख रहा है; उदाहरण के लिए Diagonal(SubMatrix(A)) अभिव्यक्ति में, Diagonal फ़ंक्शन DiagonalView<SubMatrixView<T> > प्रकार का ऑब्जेक्ट देता है, जिसे पूरी तरह से व्युत्पन्न प्रकार A पता होना चाहिए। अब, मान लें कि Scale में मैं कुछ अन्य फ़ंक्शन को कॉल करता हूं, जो या तो मूल दृश्य या मैट्रिक्स संदर्भ लेता है। यह असफल हो जाएगा क्योंकि आवश्यक View के निर्माण के लिए स्केल के तर्क के व्युत्पन्न प्रकार की आवश्यकता होती है; जानकारी नहीं है। अभी भी इसका समाधान ढूंढने पर काम कर रहे हैं।


अद्यतन

मैं का इस्तेमाल किया है क्या प्रभावी ढंग से Scale की तरह एक समारोह के दो विभिन्न संस्करणों के बीच चयन करने के लिए बूस्ट के enable_if की एक देसी संस्करण है। यह मेरे सभी मैट्रिक्स को लेबल करने और अतिरिक्त टाइपिफ़ टैग वाले वर्गों को देखने के लिए उबलता है जो इंगित करता है कि क्या वे पठनीय और लिखने योग्य और दृश्यमान हैं या न देखे जा सकते हैं। अंत में, मुझे अभी भी 2^एन अधिभार की आवश्यकता है, लेकिन अब एन केवल गैर-कॉन्स्ट तर्कों की संख्या है। अंतिम परिणाम के लिए, here देखें (यह गंभीरता से फिर से सुधारने की संभावना नहीं है)।

+0

कोई विशेष कारण क्यों स्केल() कॉन्स्ट संदर्भ द्वारा पैरामीटर स्वीकार नहीं करता है? – Naveen

+0

स्केल वास्तव में इसके तर्क को स्केल करना चाहिए, इस प्रकार यह स्थिर नहीं हो सकता है। –

+1

स्केल अस्थायी मैट्रिक्स को क्यों संशोधित करता है? –

उत्तर

1

इसे ठीक करने का एक आसान तरीका संदर्भ के बजाय boost::shared_ptr< MatrixBase<T> > का उपयोग करना होगा।

0

हो सकता है, आपको const का उपयोग करना चाहिए। ?

template <class T> 
void Scale(const MatrixBase<T> &A, const T &scale_factor); 
+0

नहीं, यह नहीं होना चाहिए, स्केल ए –

+0

@Victor संशोधित करेगा: यदि स्केल ए को संशोधित करता है, तो आपको अस्थायी रूप से पास नहीं करना चाहिए। हालांकि, अगर आप * वास्तव में * करना चाहते हैं और यदि आपका प्लेटफ़ॉर्म विंडोज है, तो आप विजुअल स्टूडियो के साथ कोड को गैर-कॉन्स्ट संदर्भ के रूप में संकलित कर सकते हैं। लेकिन मुझे यकीन नहीं है कि अगर आप उस मामले में पारित वस्तु को संशोधित करने का प्रयास करेंगे तो क्या होगा। – Naveen

0

आप स्केल पहला तर्क के प्रकार सीमित कर रहे हैं, लेकिन आप संकलक आंकड़ा बाहर किस प्रकार अपने आप ही उपयुक्त होगा, इस तरह कर सकते हैं:

template <class M,class T> 
void Scale(M A, const T &scale_factor); 
+0

हां, मैं ऐसा कर सकता था, लेकिन इससे दूसरी समस्या होती है। मेरे पास वेक्टरबेस, वेक्टर, वेक्टर व्यू आदि भी हैं और स्केल को मैट्रिक्स की तुलना में वैक्टरों के लिए अलग-अलग काम करना चाहिए। शायद आप सुझाव दे सकते हैं कि इस अतिरिक्त जटिलता को कैसे शामिल किया जाए। –

+0

अतिरिक्त समस्याएं: मूल्य द्वारा पारित नहीं किया जा सकता है; यह संभावित रूप से एक बड़ी प्रतिलिपि हो सकता है। दूसरा, यदि यह संदर्भ द्वारा पारित किया गया है, तो हम उस समस्या पर वापस आ गए हैं जहां सामान्य matrices ठीक से पारित हो जाते हैं, लेकिन विचार ढेर पर अस्थायी हैं, इसलिए यह काम नहीं करेगा। –

0

का उपयोग न करें संदर्भ, मूल्य से गुजरती हैं।

यदि आवश्यक हो, तो elision की प्रतिलिपि आपके लिए अनुकूलन करें।

7

इसका टेम्पलेट्स से कोई लेना देना नहीं है। आपका उदाहरण

Scale(Diagonal(A), 2.0); 

f(g(v),c); 

का सामान्यीकरण किया जा सकता है सी ++ 03 में, यह करने के लिए या तो प्रति प्रति या const संदर्भ प्रति पारित किया जा f() को पहले पैरामीटर की आवश्यकता है। कारण यह है कि g() एक अस्थायी, एक रावलू देता है। हालांकि, रावल केवल const संदर्भों से बंधे हैं, लेकिन गैर-कॉन्स्ट संदर्भों के लिए नहीं। यह स्वतंत्र है कि टेम्पलेट्स, एसएफआईएनएई, टीएमपी या क्या शामिल नहीं हैं। यह वही तरीका है जिसकी भाषा (वर्तमान में) है।

इसके पीछे एक तर्क भी है: यदि g() अस्थायी लौटाता है, और f() उस अस्थायी को संशोधित करता है, तो किसी को भी संशोधित अस्थायी "देखने" का मौका नहीं मिलता है। इस प्रकार संशोधन व्यर्थ में किया जाता है और पूरी चीज सबसे अधिक संभावना है।

जहां तक ​​मैंने आपको समझा, g() का परिणाम एक अस्थायी है जो किसी अन्य ऑब्जेक्ट (v) पर एक दृश्य है, इसलिए इसे संशोधित करने से v संशोधित होगा। लेकिन अगर ऐसा है, तो वर्तमान सी ++ में, g() का परिणाम const होना चाहिए (ताकि यह const संदर्भ से जुड़ा हो या इसे कॉपी किया जाना चाहिए। const मुझे "गंध" गलत है, जिससे यह देखने के लिए सस्ते लग रहा है शायद सबसे अच्छी बात होगी।

हालांकि, इसके लिए और भी कुछ है। सी ++ 1 एक्स पेश करेगा जिसे रेवल्यू संदर्भ कहा जाता है। जिसे हम "संदर्भ" के रूप में जानते हैं, उसे तब या तो लालू संदर्भ या रावल संदर्भों में विभाजित किया जाएगा। आप "l/rvalue-ness" के आधार पर कार्यों को रैवल्यू संदर्भ और यहां तक ​​कि अधिभारित करने में सक्षम होंगे। यह क्लास डिजाइनरों को प्रतिलिपि दाहिने हाथों के लिए कॉपी सीटीओआर और असाइनमेंट को अधिभारित करने और उन्हें दाएं हाथ के पक्षों के मूल्यों को "चोरी" करने की अनुमति देने के लिए सोचा गया था, ताकि रावल की प्रतिलिपि बनाना सस्ता हो। लेकिन आप शायद इसे Scale प्राप्त करने के लिए उपयोग कर सकते हैं और इसे संशोधित कर सकते हैं।

दुर्भाग्य से आपका कंपाइलर अभी तक रैवलू संदर्भों का समर्थन नहीं करता है।


संपादित करें (अनुवर्ती प्रश्न):

आप f(T&) साथ f(T) ओवरलोड नहीं कर सकते हैं प्राप्त करने के लिए आप क्या चाहते हैं। जबकि केवल पूर्व का उपयोग राजस्व के लिए किया जाएगा, जबकि लालसा या तो तर्क को समान रूप से अच्छी तरह से बांध सकते हैं, इसलिए f को एक आभासी के साथ संदिग्ध करना संदिग्ध है और परिणाम संकलन-समय त्रुटि में होता है।

template <class T> 
void Scale(MatrixBase<T> &matrix, const T &scale_factor); 

template <class T> 
void Scale(DiagonalView<T> view, const T &scale_factor); 

क्या मैं याद कर रहा हूँ है:

हालांकि, DiagonalView के लिए एक अधिभार होने के साथ गलत क्या है?


एक और संपादित:

मैं के बाद से वहाँ वर्तमान में अधिक से अधिक 5 बार देखा गया है, और वहाँ स्केल की तरह कई दर्जन कार्य हैं, तो भार के के एक हास्यास्पद बड़ी संख्या की आवश्यकता होगी।

फिर आपको उन प्रकारों को एक साथ समूहित करने की आवश्यकता होगी जिन्हें एक ही तरीके से संभाला जा सकता है। आप समूह करने के लिए कुछ सरल टेम्पलेट-मेटा सामान का उपयोग कर सकते हैं। मेरे सिर के ऊपर बंद:

template<bool B> 
struct boolean { enum { result = B }; }; 

template< typename T > 
class some_matrix { 
    public: 
    typedef boolean<false> is_view; 
    // ... 
}; 

template< typename T > 
class some_view { 
    public: 
    typedef boolean<true> is_view; 
    // ... 
}; 

namespace detail { 
    template< template<typename> class Matrix, typename T > 
    void Scale(Matrix<T>& matrix, const T& scale_factor, boolean<true>) 
    { 
    /* scaling a matrix*/ 
    } 
    template< template<typename> class Matrix, typename T > 
    void Scale(View<T>& matrix, const T& scale_factor, boolean<true>) 
    { 
    /* scaling a view */ 
    } 
} 

template< template<typename> class Matrix, typename T > 
inline void Scale(Matrix<T>& matrix, const T& scale_factor) 
{ 
    detail::Scale(matrix, scale_factor, typename Matrix<T>::is_view()); 
} 

यह विशेष रूप से सेटअप/समूह वास्तव में अपनी आवश्यकताओं फिट नहीं हो सकता है, लेकिन आप तरीके कि खुद के लिए फिट में इस तरह सेटअप कुछ कर सकते हैं।

+0

मैं अब इस बिंदु को पूरी तरह से समझता हूं, लेकिन मैंने एक और फॉलोअप प्रश्न जोड़ा है। –

+0

मुझे तब से हास्यास्पद रूप से बड़ी संख्या में अधिभार की आवश्यकता होगी, क्योंकि वर्तमान में 5 से अधिक विचार हैं, और स्केल जैसे कई दर्जन कार्य हैं। –

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