2013-02-17 17 views
10

मैं जो मैं एक चर के आकार पाने के लिए उपयोग करने के एक वर्ग टेम्पलेट है:कॉन्स्ट और गैर स्थिरांक टेम्पलेट विशेषज्ञता

template <class T> 
class Size 
{ 
    unsigned int operator() (T) {return sizeof(T);} 
}; 

यह ठीक काम करता है, लेकिन तार के लिए मैं sizeof के बजाय strlen उपयोग करना चाहते हैं:

template <> 
class Size<char *> 
{ 
    unsigned int operator() (char *str) {return strlen(str);} 
}; 

समस्या तब होती है जब मैं कॉन्स char के साथ आकार का उदाहरण बना देता हूं * यह अनन्य संस्करण में जाता है। मैं सोच रहा था कि टेम्पलेट विशेषज्ञता पर char * के दोनों कॉन्स्ट और गैर-कॉन्स संस्करणों को कैप्चर करने का कोई तरीका है या नहीं? धन्यवाद। इस तकनीक

+1

मैं इस आश्वस्त नहीं कर रहा हूँ एक है अच्छा विचार। उस मामले के बारे में क्या है जहां आपके पास '(const) char *' है जो स्ट्रिंग पर इंगित नहीं करता है? –

+0

क्या यह केवल 'const' संस्करण को विशेषज्ञ करने के लिए काम करता है? – Bingo

+0

तब जब आप एक गैर कॉन्स चार पास करते हैं * यह विशेषज्ञता का उपयोग नहीं करता है। –

उत्तर

9

उपयोग:

#include <type_traits> 

template< typename T, typename = void > 
class Size 
{ 
    unsigned int operator() (T) {return sizeof(T);} 
}; 

template< typename T > 
class Size< T, typename std::enable_if< 
       std::is_same< T, char* >::value || 
       std::is_same< T, const char* >::value 
       >::type > 
{ 
    unsigned int operator() (T str) { /* your code here */ } 
}; 

संपादित करें: कैसे वर्ग परिभाषा के बाहर पद्धतियां निर्धारित करने का उदाहरण।

EDIT2: संभवतः लंबी और जटिल स्थिति को दोहराने से बचने के लिए सहायक सहायक जोड़ा गया।

EDIT3: सरलीकृत सहायक।

#include <type_traits> 
#include <iostream> 

template< typename T > 
struct my_condition 
    : std::enable_if< std::is_same< T, char* >::value || 
        std::is_same< T, const char* >::value > 
{}; 

template< typename T, typename = void > 
struct Size 
{ 
    unsigned int operator() (T); 
}; 

template< typename T > 
struct Size< T, typename my_condition<T>::type > 
{ 
    unsigned int operator() (T); 
}; 

template< typename T, typename Dummy > 
unsigned int Size< T, Dummy >::operator() (T) 
{ 
    return 1; 
} 

template< typename T > 
unsigned int Size< T, typename my_condition<T>::type >::operator() (T) 
{ 
    return 2; 
} 

int main() 
{ 
    std::cout << Size<int>()(0) << std::endl; 
    std::cout << Size< char* >()(0) << std::endl; 
    std::cout << Size< const char* >()(0) << std::endl; 
} 

जो प्रिंट

1 
2 
2 
+1

धन्यवाद, मैं 'typename = void' वाक्यविन्यास से अपरिचित हूं, मैं ऑपरेटर() को कैसे परिभाषित करूं यदि मैं कक्षा के बाहर फ़ंक्शन बॉडी लिखना चाहता हूं और किसी भी मामले में, रेखांकित नहीं करना चाहता हूं? –

+1

यह 'टाइपनाम डमी = शून्य' के लिए बस छोटा है जहां 'डमी' का कभी भी उपयोग नहीं किया जाता है। मैं कक्षा के बाहर 'ऑपरेटर()' को परिभाषित करने के उत्तर को जांच और बढ़ाऊंगा ... –

+0

धन्यवाद और विशेष मामले के लिए मुझे फ़ंक्शन परिभाषा में पूरी लंबी चीज़ लिखनी होगी? –

4

एक तरह से क्रम में एक सहायक समारोह का उपयोग करने के लिए यदि टेम्पलेट प्रकार एक char * या एक char const * है निर्धारित करने के लिए है। आप इसे एक साधारण संरचना के साथ कर सकते हैं। फिर आप अपने आकार की संरचना के उचित विशेषज्ञता का चयन करने के लिए SFINAE का उपयोग कर सकते हैं।

#include <cstring> 
#include <iostream> 

#include <boost/utility/enable_if.hpp> 

template<typename T> 
struct is_cstring { 
    enum { value = false }; 
}; 

template<> 
struct is_cstring<char *> { 
    enum { value = true }; 
}; 

template<> 
struct is_cstring<char const *> { 
    enum { value = true }; 
}; 

template<typename T, typename = void> 
struct Size; 

template<typename T> 
struct Size<T, typename boost::disable_if<is_cstring<T> >::type> { 
    unsigned int operator()(T const &) const { 
    return sizeof(T); 
    } 
}; 

template<typename T> 
struct Size<T, typename boost::enable_if<is_cstring<T> >::type> { 
    unsigned int operator()(T const &str) const { 
    return strlen(str); 
    } 
}; 

int main() { 
    std::string blah = "afafasa"; 
    char *x = "asdfsadsad"; 

    std::cout << Size<int>()(4) << std::endl; 
    std::cout << Size<char const *>()("blahblah") << std::endl; 
    std::cout << Size<char *>()(x) << std::endl; 
} 

मुद्रित परिणाम है:

4 
8 
10 
-1

सरल समाधान const char * एक के साथ char * विशेषज्ञता की जगह है। यह char * के लिए भी काम करेगा।

template <> 
class Size<const char *> 
{ 
    unsigned int operator() (const char *str) {return strlen(str);} 
}; 
+0

-1 यदि कोई 'आकार :: ऑपरेटर() 'का उपयोग करता है, तो यह आपके द्वारा दिखाए गए विशेष संस्करण का उपयोग नहीं करेगा। –

0

और तुम भी निश्चित रूप से लिखने के लिए, सक्षम होना चाहिए:

template <> 
class Size<const char *> 
{ 
    unsigned int operator() (const char *str) {return strlen(str);} 
}; 

template <> 
class Size<char *> : public Size<const char *> 
{ }; 

... और, आप की आवश्यकता चाहिए करने के लिए:

template <size_t size> 
class Size<char[size]> : public Size<const char *> 
{ }; 

template <size_t size> 
class Size<const char[size]> : public Size<const char *> 
{ }; 
संबंधित मुद्दे