2016-08-24 11 views
8

में टाइप बनाम टाइपिफ़ में टाइपिफ़ाई शैक्षिक उद्देश्यों के लिए मैं ईजिन स्रोत कोड देख रहा हूं। मैंने देखा है कि पदानुक्रम में प्रत्येक ठोस वर्ग टेम्पलेट X के लिए, internal::traits<X> परिभाषित किया गया है। एक विशिष्ट उदाहरण Matrix.h में पाया जा सकता:कक्षा

namespace internal { 
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> 
struct traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > 
{ 
    typedef _Scalar Scalar; 
    typedef Dense StorageKind; 
    typedef DenseIndex Index; 
    typedef MatrixXpr XprKind; 
    enum { 
    RowsAtCompileTime = _Rows, 
    ColsAtCompileTime = _Cols, 
    MaxRowsAtCompileTime = _MaxRows, 
    MaxColsAtCompileTime = _MaxCols, 
    Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, 
    CoeffReadCost = NumTraits<Scalar>::ReadCost, 
    Options = _Options, 
    InnerStrideAtCompileTime = 1, 
    OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime 
    }; 
}; 
} 

अब मैं लक्षण समझ में मौजूदा वर्गों है कि आप नए कोड के कुछ टुकड़े से संबंधित अतिरिक्त जानकारी के साथ संशोधित करने के लिए नहीं करना चाहते हैं का विस्तार करने का एक तरीका हो सकता है। उदाहरण के लिए, वर्ग टेम्पलेट Foo<class TAllocator> का एक उपयोगकर्ता मौजूदा स्मृति allocators FastAlloc और AlignedAlloc का उपयोग करना चाहते हो सकता है, लेकिन फू पता करने के लिए इन दोनों के साथ इंटरफेस करने के लिए कैसे की जरूरत है, और इस तरह के एक FooTraits<AlignedAlloc>::allocate() और FooTraits<FastAlloc>::allocate() के रूप में उपयोगकर्ता, द्वारा परिभाषित कर रहे है जो बदले में Foo द्वारा उपयोग किया जाता है।

इस मामले में, हालांकि, मैं आसानी से समस्या सिर्फ प्रत्येक व्युत्पन्न वर्ग में Scalar निर्दिष्ट करने के साथ नहीं दिख रहा है, यानी है Matrix परिभाषित Matrix::Scalar वर्ग शरीर में एक typedef का उपयोग कर। एक विशेषता वर्ग का उपयोग करने का लाभ यहां क्या है? क्या यह सिर्फ कोड को साफ रखने के प्रयोजनों के लिए है, यानी प्रत्येक वर्ग के सभी प्रासंगिक गुणों को गुण वर्ग में संग्रहीत करना है?

निकोल Bolas की प्रतिक्रिया के अनुसार संपादित करें: मैं समझता हूँ कि इन typedefs के कुछ रखा जाना "आंतरिक", यानी जरूरत हो सकती है उपयोगकर्ता है, जो लक्षण वर्ग की व्याख्या करता है के संपर्क में नहीं किया जाना चाहिए।

template<typename Derived> class MatrixBase 
    : public DenseBase<Derived> 
{ 
    public: 

    typedef MatrixBase StorageBaseType; 
    typedef typename internal::traits<Derived>::StorageKind StorageKind; 
    typedef typename internal::traits<Derived>::Index Index; 
    typedef typename internal::traits<Derived>::Scalar Scalar; 
    typedef typename internal::packet_traits<Scalar>::type PacketScalar; 
    typedef typename NumTraits<Scalar>::Real RealScalar; 

इस मूल प्रश्न के लिए हमें वापस लाता है: यह Matrix के आधार वर्ग में एक typedef के माध्यम से समझ बनाने के लिए, हालांकि, बाहर की दुनिया के इन typedefs में से कुछ, इस तरह के Scalar के रूप में, हैं उपलब्ध लगता है : Scalar क्यों नहीं Matrix में केवल एक टाइपिफ़ है? स्टाइलिस्ट पसंद से अलग कोई कारण है?

उत्तर

5

मुझे संदेह है कि, चूंकि विशेषता वर्ग internal है, यह एक विशेषता वर्ग का उपयोग करने का मुद्दा है। यही है, इन चीजों को आंतरिक रखने के लिए। इस तरह, Matrix में अपने निजी इंटरफ़ेस में भी कई विषम परिभाषाएं नहीं हैं।

अपने उदाहरण में गणना पर विचार करें। उन "enums" (उर्फ: static constexpr सी ++ 11 से पहले चर) किसी उपयोगकर्ता को इसके बारे में पता होना चाहिए जैसा दिखता नहीं है। यह एक कार्यान्वयन विस्तार है, और इसलिए इसे छुपाया जाना चाहिए।


MatrixBase की समस्या एक सीआरटीपी मुद्दा है।

देखें, Matrix इस तरह परिभाषित किया जाएगा:

  1. तो Matrix पहले से ही एक वर्ग प्रकार के रूप में घोषित नहीं किया गया है, तो यह:

    class Matrix : public MatrixBase<Matrix> 
    

    यह आंशिक परिभाषा होने के लिए 2 बातें का कारण बनता है एक कानूनी वर्ग बन जाता है जिसका नाम संदर्भित और उपयोग किया जा सकता है।

  2. टेम्पलेट MatrixBaseMatrix प्रकार के साथ तत्काल होना चाहिए। अभी

समस्या यहां है कि "अभी", Matrix एक अधूरा वर्ग है। कंपाइलर ने अभी तक उस परिभाषा के शरीर में प्रवेश नहीं किया है, इसलिए संकलक को इसके आंतरिक के बारे में कुछ भी पता नहीं है। लेकिन MatrixBase अभी तत्काल होना चाहिए।

इसलिए, MatrixBaseDerived कक्षा में से किसी भी का उपयोग नहीं कर सकता है। यदि Matrix में इसमें कुछ टाइपिफ़ है, MatrixBase<Derived> नहीं देख सकता है।

अब, MatrixBase<Derived> के सदस्य कार्य Derived में परिभाषाओं को देख सकते हैं, क्योंकि पूर्ण वर्ग परिभाषित होने के बाद परिभाषित किया गया है। भले ही उन कार्यों को कक्षा के दायरे में परिभाषित किया गया हो।

लेकिन आपके पास Derived के गुणों के गुण नहीं हो सकते हैं। इसलिए लक्षण संकेत। गुण वर्ग MatrixBase को परिभाषित करने के लिए अपूर्ण प्रकार के आधार पर एक विशेषज्ञता का उपयोग कर सकते हैं।

+0

मैं उन परिभाषाओं में से कुछ के लिए तर्क समझता हूं। हालांकि, जिस वर्ग से 'मैट्रिक्स' विरासत में मिलता है, 'मैट्रिक्सबेस' सार्वजनिक रूप से 'स्लारर' जैसे कुछ टाइपिफ़ को परिभाषित करता है, जो हमें शुरुआत में वापस लाता है - क्यों शुरू करने के लिए मैट्रिक्स में 'स्केलर' को परिभाषित नहीं किया जाता है? –

+0

@MoosHueting: संपादन देखें। –

+0

बहुत स्पष्ट - समय लेने के लिए बहुत बहुत धन्यवाद! –

3

traits कक्षा का मुख्य कारण CRTP में रिकर्सिव निर्भरताओं से बचने के लिए है। इसके बिना, हम कुछ इस तरह खत्म हो जाएंगे:

template <typename T> 
struct Matrix : Base<Matrix<T>> { 
    typedef T Scalar; 
}; 
template <typename Derived> 
struct Base { 
    typename Derived::Scalar foo(); 
}; 

जो कुछ परिस्थितियों में संकलित करने में विफल रहता है। मूल रूप से, यह वर्ग traits को Matrix की घोषणा के बिना पूरी तरह से घोषित करने की अनुमति देता है।

+0

आह, मैं देखता हूं, समझ में आता है। धन्यवाद! –