2008-09-29 13 views
15

मैंने http://codepad.org/ko8vVCDF पर एक नमूना प्रोग्राम लिखा जो टेम्पलेट फ़ंक्शन का उपयोग करता है।टेम्पलेट फ़ंक्शन को प्रतिबंधित करें

टेम्पलेट फ़ंक्शन को केवल संख्याओं का उपयोग करने के लिए मैं कैसे प्रतिबंधित करूं? (int, डबल इत्यादि)

#include <vector> 
#include <iostream> 

using namespace std; 

    template <typename T> 
T sum(vector<T>& a) 
{ 
    T result = 0; 
    int size = a.size(); 
    for(int i = 0; i < size; i++) 
    { 
     result += a[i]; 
    } 

    return result; 
} 

int main() 
{ 
    vector<int> int_values; 
    int_values.push_back(2); 
    int_values.push_back(3); 
    cout << "Integer: " << sum(int_values) << endl; 

    vector<double> double_values; 
    double_values.push_back(1.5); 
    double_values.push_back(2.1); 
    cout << "Double: " << sum(double_values); 

    return 0; 
} 
+2

आपके प्रश्न में एक कॉमा सहायक होगा। –

+1

@ डैनियलरोड्रिगुएज़: निष्पक्ष होने के लिए, वहां एक अल्पविराम है ... – sehe

+0

"संख्या" क्या है? – curiousguy

उत्तर

17

टेम्पलेट को प्रतिबंधित करने का एकमात्र तरीका यह है कि यह आपके द्वारा इच्छित प्रकारों से कुछ उपयोग करता है, अन्य प्रकारों के पास नहीं है।

तो, आप, आदि के साथ एक पूर्णांक, उपयोग + का निर्माण और एक प्रति निर्माता + =, फोन

किसी भी प्रकार की है कि इन सब के अपने कार्य के साथ काम करेंगे - अगर मैं एक नया बनाने के लिए, तो टाइप करें कि इन सुविधाओं में, आपका फ़ंक्शन इस पर काम करेगा - जो कि बढ़िया है, है ना?

यदि आप इसे और अधिक प्रतिबंधित करना चाहते हैं, तो अधिक फ़ंक्शंस का उपयोग करें जो केवल आपके इच्छित प्रकार के लिए परिभाषित किए गए हैं।

इस लागू करने के लिए एक और तरीका है एक लक्षण टेम्पलेट बनाने के द्वारा है - इस

template<class T> 
SumTraits 
{ 
public: 
    const static bool canUseSum = false; 
} 

और फिर वर्गों के लिए यह विशेषज्ञ की तरह कुछ तुम ठीक होना चाहते हैं:

template<> 
class SumTraits<int> 
{ 
    public: 
    const static bool canUseSum = true; 
}; 
में

फिर अपने कोड, आप

if (!SumTraits<T>::canUseSum) { 
    // throw something here 
} 

संपादित करें: टिप्पणियों में उल्लिखित अनुसार, आप बी का उपयोग कर सकते हैं OOST_STATIC_ASSERT इसे रन-टाइम एक

+3

आप संकलन समय पर स्थिति को लागू करने के लिए BOOST_STATIC_ASSERT का भी उपयोग कर सकते हैं। – ChrisN

+0

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

+0

SFINAE इसका समाधान है, BOOST_STATIC_ASSERT –

1

आप इस मामले में प्रकारों को प्रतिबंधित क्यों करना चाहते हैं? टेम्पलेट्स "स्थिर बतख टाइपिंग" की अनुमति देते हैं, इसलिए इस मामले में आपके sum फ़ंक्शन द्वारा अनुमत कुछ भी अनुमति दी जानी चाहिए। विशेष रूप से, T का एकमात्र ऑपरेशन एड-असाइनमेंट और 0 से प्रारंभिकता है, इसलिए उन दो प्रकार के संचालन का समर्थन करने वाला कोई भी प्रकार काम करेगा। यह टेम्पलेट्स की सुंदरता है।

(आप T result = T(); या पसंद करने के लिए अपने initialiser बदल, तो यह दोनों नंबर और तार के लिए भी काम करेगा।)

+1

इसे और अधिक प्रकार सुरक्षित बनाएं। –

+1

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

+1

तो उदाहरण के लिए वर्तमान में यह + = का उपयोग करता है। यदि बाद में + का उपयोग करने के लिए बदल जाता है, तो एक उपयोगकर्ता जिसका प्रकार केवल + = का समर्थन करता है, एक फसल आ जाएगा। उदाहरण के लिए यह सरल है, मैं किसी अन्य व्यावहारिक कार्यान्वयन परिवर्तन के बारे में नहीं सोच सकता, और ओवरलोडिंग + = और नहीं + किसी भी तरह की परेशानी के लिए पूछ रहा है, लेकिन उम्मीद है कि yswim। –

18

आप कुछ इस तरह कर सकते हैं::

template <class T> 
class NumbersOnly 
{ 
private: 
    void ValidateType(int &i) const {} 
    void ValidateType(long &l) const {} 
    void ValidateType(double &d) const {} 
    void ValidateType(float &f) const {} 

public: 
    NumbersOnly() 
    { 
     T valid; 
     ValidateType(valid); 
    }; 
}; 

आप अगर आप एक NumbersOnly कि एक ValidateType अधिभार नहीं है बनाने की कोशिश एक त्रुटि प्राप्त होगी

मैं गूगल पर निम्नलिखित पाया :

NumbersOnly<int> justFine; 
NumbersOnly<SomeClass> noDeal; 
+0

अच्छा काम। http://lenniedevilliers.codepad.org/aR6xi14c –

+4

मैंने संक्षेप में सोचा कि यह गलत था (क्षमा करें), लेकिन विधि हस्ताक्षर में महत्वपूर्ण है - यह एक प्रकार के साथ तत्कालता को रोकता है जो केवल int में परिवर्तनीय है। तो चार, हस्ताक्षरित int, और एक वर्ग जो ऑपरेटर int() को ओवरलोड करता है, सभी को अपेक्षित रूप से प्रतिबंधित कर दिया जाता है। –

+1

जैसा कि "लंबा डबल" है, जो शायद आप नहीं चाहते हैं। लेकिन यह सी ++ मानक से प्रत्येक अंकगणितीय प्रकार को सूचीबद्ध करने का सिर्फ एक प्रश्न है। –

1

वास्तव में, इसे और अधिक कठोर बनाने की आवश्यकता नहीं है। स्ट्रिंग संस्करण (क्रिस जेस्टर-यंग द्वारा दी गई डिफ़ॉल्ट कन्स्ट्रक्टर शैली का उपयोग करके) here ...

अतिप्रवाह के लिए भी देखभाल करें - आपको मध्यवर्ती परिणामों (या आउटपुट परिणाम) के लिए एक बड़ा प्रकार की आवश्यकता हो सकती है)। मेटा प्रोग्रामिंग के दायरे में आपका स्वागत है, फिर :)

2

की बजाय संकलन-समय जांच करने के लिए यह है कि आप इसे कैसे करते हैं।

उदाहरण के लिए डबल के लिए टेम्पलेट विशेषज्ञता पर टिप्पणी करें .. और यह आपको पैरामीटर के रूप में डबल के साथ उस फ़ंक्शन को कॉल करने की अनुमति नहीं देगा। चाल यह है कि यदि आप किसी प्रकार के साथ योग को कॉल करने का प्रयास करते हैं जो IsNumber की विशेषज्ञता में नहीं है, तो सामान्य कार्यान्वयन कहा जाता है, और यह कार्यान्वयन कुछ अनुमति नहीं देता है (एक निजी कन्स्ट्रक्टर को कॉल करें)।

त्रुटि संदेश तब तक सहज नहीं है जब तक कि आप IsNumber क्लास को किसी त्रुटि संदेश की तरह मानते हैं।

#include <vector> 
#include <iostream> 

using namespace std; 

template<class T> struct IsNumber{ 
private: 
IsNumber(){} 
}; 

template<> struct IsNumber<float>{ 
    IsNumber(){}; 
}; 

template<> struct IsNumber<double>{ 
    IsNumber(){}; 
}; 

template<> struct IsNumber<int>{ 
    IsNumber(){}; 
}; 

template <typename T> 
T sum(vector<T>& a) 
{ 
IsNumber<T> test; 
T result = 0; 
int size = a.size(); 
for(int i = 0; i < size; i++) 
{ 
    result += a[i]; 
} 

return result; 
} 




int main() 
{ 
vector<int> int_values; 
int_values.push_back(2); 
int_values.push_back(3); 
cout << "Integer: " << sum(int_values) << endl; 

vector<double> double_values; 
double_values.push_back(1.5); 
double_values.push_back(2.1); 
cout << "Double: " << sum(double_values); 

return 0; 
} 
20

यह SFINAE का उपयोग करके संभव है, और या तो बूस्ट या 11

बूस्ट सी ++ से सहायकों का उपयोग करके आसान बना दिया:

#include <vector> 
#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits/is_arithmetic.hpp> 

template<typename T> 
    typename boost::enable_if<typename boost::is_arithmetic<T>::type, T>::type 
     sum(const std::vector<T>& vec) 
{ 
    typedef typename std::vector<T>::size_type size_type; 
    T result; 
    size_type size = vec.size(); 
    for(size_type i = 0; i < size; i++) 
    { 
    result += vec[i]; 
    } 

    return result; 
} 

सी ++ 11:

#include <vector> 
#include <type_traits> 

template<typename T> 
    typename std::enable_if<std::is_arithmetic<T>::value, T>::type 
     sum(const std::vector<T>& vec) 
{ 
    T result; 
    for (auto item : vec) 
    result += item; 
    return result; 
} 
+1

'वेक्टर :: ::' hum ... – curiousguy

+0

@curiousguy: इस स्निपलेट में मैंने ओपी के शामिल (वेक्टर) और उपयोग (एसडीडी) को माना। –

+0

@LeonTimmermans तो? – curiousguy

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