2010-03-11 16 views
7

का उपयोग मैं सी ++ में दो आदिम प्रकारों को सही पदोन्नति प्रकार निर्धारित करने के लिए टेम्पलेट्स के एक सेट के साथ खेल रहा हूं। विचार यह है कि यदि आप एक कस्टम संख्यात्मक टेम्पलेट को परिभाषित करते हैं, तो आप टेम्पलेट्स को पारित कक्षा के आधार पर ऑपरेटर + फ़ंक्शन का रिटर्न प्रकार निर्धारित करने के लिए इनका उपयोग कर सकते हैं। उदाहरण के लिए:सी ++ अंकगणितीय संवर्धन शीर्षलेख

// Custom numeric class 
template <class T> 
struct Complex { 
    Complex(T real, T imag) : r(real), i(imag) {} 
    T r, i; 
// Other implementation stuff 
}; 

// Generic arithmetic promotion template 
template <class T, class U> 
struct ArithmeticPromotion { 
    typedef typename X type; // I realize this is incorrect, but the point is it would 
           // figure out what X would be via trait testing, etc 
}; 

// Specialization of arithmetic promotion template 
template <> 
class ArithmeticPromotion<long long, unsigned long> { 
    typedef typename unsigned long long type; 
} 

// Arithmetic promotion template actually being used 
template <class T, class U> 
Complex<typename ArithmeticPromotion<T, U>::type> 
operator+ (Complex<T>& lhs, Complex<U>& rhs) { 
    return Complex<typename ArithmeticPromotion<T, U>::type>(lhs.r + rhs.r, lhs.i + rhs.i); 
} 

आप इन पदोन्नति टेम्पलेट का उपयोग करते हैं, तो आप कम या ज्यादा अपने उपयोगकर्ता परिभाषित प्रकार के रूप में यदि वे एक ही पदोन्नति नियमों उन्हें लागू किया जा रहा के साथ पुरातन रहे इलाज कर सकते हैं। तो, मुझे लगता है कि मेरे पास यह सवाल है क्या यह ऐसा कुछ होगा जो उपयोगी हो सकता है? और यदि हां, तो उपयोग की आसानी के लिए आप किस प्रकार के सामान्य कार्यों को दूर करना चाहते हैं? मैं इस धारणा पर काम कर रहा हूं कि अकेले पदोन्नति टेम्पलेट्स व्यावहारिक गोद लेने के लिए अपर्याप्त होंगे।

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

टीएल; डीआर: आप किस तरह के सहायक टेम्पलेट्स को गणित के बाहर एक अंकगणितीय पदोन्नति शीर्षलेख में ढूंढने की उम्मीद करेंगे जो पदोन्नति करता है?

+0

मुझे लगता है कि आप अंत में कुछ चर (विभिन्न प्रकार के) के लिए अच्छी तरह से प्रचारित परिणाम असाइन करने जा रहे हैं, इसलिए मैं इसके लिए अधिक व्यावहारिक उपयोग नहीं देख सकता। शायद सी ++ 0x में ** ऑटो ** के साथ, लेकिन फिर भी मुझे लगता है कि ** decltype ** अधिकतर नौकरी का अधिक आसानी से ख्याल रख सकता है। यह पता चला है – UncleBens

+0

रूप में, यह CommonType struct, जो decltype का लाभ उठाता है सही प्रकार यह पता लगाने की के रूप में C++ 0x में लागू किया जाएगा। यदि कोई पदोन्नति/रूपांतरण के मानक के नियमों के संबंध में पूरी तरह से समान व्यवहार चाहता है, तो उन्हें केवल टेम्पलेट्स की कम्यूटिव विविधताओं को लिखना होगा। – BenTrofatter

उत्तर

2

यह निश्चित रूप से उपयोगी है - हम गणित पुस्तकालय में इन प्रकार की चीजों का उपयोग करते हैं जो मैं अभिव्यक्तियों में मध्यवर्ती मूल्यों को सही ढंग से टाइप करने के लिए काम करता हूं। उदाहरण के लिए, यदि आप एक टेम्प्लेट की गई इसके अलावा ऑपरेटर हो सकता है:

template<typename Atype, typename Btype> 
type_promote<Atype, Btype>::type operator+(Atype A, Btype B); 

इस तरह, आप एक सामान्य ऑपरेटर है कि विभिन्न तर्क प्रकार संभाल लेंगे लिख सकते हैं, और यह उचित प्रकार का कोई मान में परिशुद्धता नुकसान से बचने के होगा अभिव्यक्ति जो यह प्रकट होती है। यह इन ऑपरेटरों के भीतर आंतरिक चर को सही ढंग से घोषित करने के लिए भी उपयोगी है (वेक्टर रकम जैसी चीजों में)।

इस सवाल के लिए कि इनके साथ क्या जाना चाहिए: मैंने अभी हमारे स्रोत कोड में चेक किया है जहां हम उन्हें परिभाषित करते हैं, और हमारे पास केवल सरल अंकगणित प्रमोशन घोषणा है जो आप वर्णन करते हैं - परिसर को हल करने के लिए तीन सामान्य संस्करण विशिष्ट वास्तविक वास्तविक लोगों का उपयोग करते हुए, जटिल वास्तविक, और असली-वास्तविक रूपों का वास्तविक, वास्तविक वास्तविक लोगों की सूची - कोड की लगभग 50 पंक्तियां। हमारे पास उनके साथ कोई अन्य सहायक टेम्पलेट नहीं है, और यह (हमारे उपयोग से) ऐसा नहीं लगता है कि हम किसी भी प्राकृतिक हैं जिनका उपयोग हम करेंगे।

(Fwiw, अगर आप इस खुद लिखते हैं, http://www.codesourcery.com/vsiplplusplus/2.2/download.html से हमारे स्रोत डाउनलोड करें, और src/vsip/core/promote.hpp बाहर निकलने के लिए नहीं करना चाहती। हालांकि यह है कि, यहां तक ​​कि हमारे पुस्तकालय का हिस्सा बीएसडी लाइसेंस प्राप्त है कि में है वास्तव में ऐसा नहीं कहना फ़ाइल में ही।)

12

इसके लिए, आप ?: ऑपरेटर का उपयोग कर सकते हैं। यह आपको दो प्रकार के बीच आम प्रकार देगा। सबसे पहले, यदि दो प्रकार समान हैं, तो आप ठीक हैं। फिर, यदि प्रकार भिन्न होते हैं, तो आप ?: का आह्वान करते हैं और देखते हैं कि आप किस प्रकार वापस आते हैं।

आप गैर पदोन्नत प्रकार char, short और उनके अहस्ताक्षरित/हस्ताक्षर किए संस्करणों उसके बाद से भिन्न प्रकार के इस तरह के ऑपरेंड के दो के लिए लागू विशेष मामले की जरूरत है, परिणाम उनमें से कोई भी हो जाएगा। आपको उस मामले की भी देखभाल करने की आवश्यकता है जहां दो वर्गों को पदोन्नत अंकगणितीय प्रकारों में परिवर्तित किया जा सकता है। इन अधिकारों को प्राप्त करने के लिए, हम जांचते हैं कि ?: का परिणाम एक प्रचारित अंकगणितीय प्रकार है (खंड 13.6 की भावना में), और उस प्रकार का उपयोग करें।

// typedef eiher to A or B, depending on what integer is passed 
template<int, typename A, typename B> 
struct cond; 

#define CCASE(N, typed) \ 
    template<typename A, typename B> \ 
    struct cond<N, A, B> { \ 
    typedef typed type; \ 
    } 

CCASE(1, A); CCASE(2, B); 
CCASE(3, int); CCASE(4, unsigned int); 
CCASE(5, long); CCASE(6, unsigned long); 
CCASE(7, float); CCASE(8, double); 
CCASE(9, long double); 

#undef CCASE 

// for a better syntax... 
template<typename T> struct identity { typedef T type; }; 

// different type => figure out common type 
template<typename A, typename B> 
struct promote { 
private: 
    static A a; 
    static B b; 

    // in case A or B is a promoted arithmetic type, the template 
    // will make it less preferred than the nontemplates below 
    template<typename T> 
    static identity<char[1]>::type &check(A, T); 
    template<typename T> 
    static identity<char[2]>::type &check(B, T); 

    // "promoted arithmetic types" 
    static identity<char[3]>::type &check(int, int); 
    static identity<char[4]>::type &check(unsigned int, int); 
    static identity<char[5]>::type &check(long, int); 
    static identity<char[6]>::type &check(unsigned long, int); 
    static identity<char[7]>::type &check(float, int); 
    static identity<char[8]>::type &check(double, int); 
    static identity<char[9]>::type &check(long double, int); 

public: 
    typedef typename cond<sizeof check(0 ? a : b, 0), A, B>::type 
    type; 
}; 

// same type => finished 
template<typename A> 
struct promote<A, A> { 
    typedef A type; 
}; 

अपने Complex<T> प्रकार एक दूसरे में परिवर्तित किया जा सकता है, तो ?: एक आम प्रकार नहीं मिलेगा। आप promote विशेषज्ञ सकता है यह बताने के लिए बाहर दो Complex<T> का एक आम प्रकार आंकड़ा:

template<typename T, typename U> 
struct promote<Complex<T>, Complex<U>> { 
    typedef Complex<typename promote<T, U>::type> type; 
}; 

प्रयोग सरल है:

int main() { 
    promote<char, short>::type a; 
    int *p0 = &a; 

    promote<float, double>::type b; 
    double *p1 = &b; 

    promote<char*, string>::type c; 
    string *p2 = &c; 
} 

ध्यान दें कि वास्तविक दुनिया के लिए उपयोग करता है, तो आप सबसे अच्छा कुछ पकड़ने चाहिए मामलों मैं सादगी के लिए बाहर छोड़ दिया है, उदाहरण के <const int, int> के लिए <T, T> के लिए इसी तरह संभाला जाना चाहिए (आप सबसे अच्छा पहली पट्टी const और volatile और T* को T[N] बदलने और T&कोऔर उसके बाद वास्तविक promote टेम्पलेट पर प्रतिनिधि - i 0e boost::remove_cv<boost::decay<T>>::type दोनों को A और B दोनों को प्रतिनिधि देने से पहले)। यदि आप ऐसा नहीं करते हैं, तो check पर कॉल इन मामलों के लिए अस्पष्टता में समाप्त हो जाएगा।

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