2010-11-04 9 views
6
template < unsigned int i > 
struct t { 
    static const char *s; 
}; 
template < unsigned int i > 
const char* t<i>::s = ...; 

जहां ... है पैरामीटर "0 1 2 ... मैं -1", उदाहरण के लिए "0 1 2 3 4" i == 5 के लिए के लिए।C++: टेम्पलेट से स्ट्रिंग शाब्दिक पैदा

क्या यह संभव है? (रन-टाइम पर ऐसा करने के लिए कोई समाधान नहीं है, कृपया!)

  • जिज्ञासा से पूछे जाने वाले प्रश्न (प्रीप्रोसेसर मैक्रोज़/स्थिरांक के साथ ऐसा करना आसान होगा, लेकिन टेम्पलेट पैरामीटर के बारे में कैसे)?
  • अर्थ है: संकलन-समय उत्पन्न स्ट्रिंग अक्षरशः। अब मुझे लगता है कि const इसे मजबूर नहीं करता है, लेकिन स्ट्रिंग पीढ़ी के लिए कोई रन-टाइम मूल्यांकन फ़ंक्शन ले सकता है।
+1

यह संभव नहीं है। आप इसे प्राप्त करने की कोशिश कर रहे हैं क्या? –

+1

@Moo: जिज्ञासा, अभी तक कोई उपयोग नहीं है। यदि 'i' प्रीप्रोसेसर स्थिर था, तो यह आसान होगा, लेकिन टेम्पलेट्स के साथ मैं इसे हल करने के तरीके के बारे में सोच नहीं सकता था। – Thomas

+0

@ रेनो: टेम्पलेट, क्योंकि विभिन्न 'i' के लिए कई तात्कालिकताएं हो सकती हैं; मैं बिना किसी संरचना के इसे कैसे लिख सकता हूं? मुझे नहीं लगता कि 'टेम्पलेट < int i > कॉन्स char * s = ...;' संकलित होगा। – Thomas

उत्तर

3

नहीं, लेकिन यह संभव है:

template < unsigned int i > 
struct t { 
    static std::string s; 

    static std::string ConvertIntToString() 
    { 
    std::stringstream ss; 
    ss << i; 
    return ss.str(); 
    } 
}; 

template< unsigned int i > 
std::string t<i>::s = t<i>::ConvertIntToStr(); 

btw क्यों प्रयोग कर रहे हैं ग तार? सी ++ में std :: स्ट्रिंग क्लास है जो बेहतर है।

संपादित

मुझे लगता है कि आप टेम्पलेट विशेषज्ञता इस्तेमाल कर सकते हैं:

template < unsigned int i > 
struct t; 

template <> 
struct t<0> 
{ 
    static const char * const s; 
}; 
const char* const t<0>::s = "abc"; 

template <> 
struct t<1> 
{ 
    static const char * const s; 
}; 
const char* const t<1>::s = "123"; 
+0

रन-टाइम पर एक समाधान निश्चित रूप से ढूंढना आसान है, लेकिन यह मेरा प्रश्न नहीं था; बिंदु 'कॉन्स' था। – Thomas

+0

और निश्चित रूप से, मैं स्ट्रिंग स्थिरांक के साथ 'std :: string' प्रारंभ कर सकता हूं, लेकिन पहले इसे किसी भी तरह से उत्पन्न करना होगा! – Thomas

+0

टेम्पलेट विशेषज्ञता सामान्य समाधान प्रदान नहीं करेगी जब तक कि यह रिकर्सिव नहीं है (लेकिन फिर, मुझे रिकर्सन करने का कोई तरीका नहीं दिखाई देता है) – Thomas

1

असंभव।

क्योंकि टेम्पलेट का विस्तार संकलन समय पर किया जाता है जब संकलक केवल स्थिर मूल्य से निपट सकता है, यह जानता है। मेमोरी आवंटन (उदाहरण के लिए एक स्ट्रिंग शुरू करना) से जुड़े किसी भी ऑपरेशन को इस समय संभव नहीं है लेकिन केवल रनटाइम पर भी संभव नहीं है।

+0

लेकिन संकलक निरंतर टेम्पलेट मान जानता है, और नहीं (गतिशील) स्मृति आवंटन आवश्यक है। – Thomas

+0

लेकिन यह लंबाई चार * एस नहीं जानता है, जो स्मृति में * जेनरेट * होना चाहिए। यही कारण है कि स्ट्रिंग को टेम्पलेट पैरामीटर के रूप में अनुमति नहीं है। –

0

यह टेम्पलेट का उपयोग करना संभव नहीं है। लेकिन stringstream का उपयोग करके, string बनाना छोटा है।

string makeit(int i) 
{ 
    stringstream sstr; 

    for (int x = 0; x < i-1; x++) 
     put x and ' ' in sstr; 
    put i in sstr; 
    return sstr contents converted to string 
} 

अधिक के बारे में stringstreamcan be found here जानकारी: यहाँ छद्म कोड है।

1

कोड आप प्रस्तुत कर रहे हैं, ...

template < unsigned int i > 
struct t { 
    static const char *s; 
}; 
static const char* t::s = ...; 

... अमान्य है। t::s में बाहरी संबंध होना चाहिए। इसके अलावा, परिभाषा को templated की जरूरत है।

कोड, जैसे के साथ सीधे समस्याओं फिक्सिंग ...

template < unsigned int i > 
struct T 
{ 
    static const char * const s; 
}; 

template< unsigned i > 
const char* const T<i>::s = ...; 

... तो किसी भी वांछित तार के साथ T<i>::s आरंभ तुच्छ है।

तो, अपने कोड में त्रुटियों को मॉड्यूल करें, जवाब है "हाँ, यह केवल संभव नहीं है, यह छोटा है"।

लेकिन आप इस रूबे गोल्डबर्ग योजना को एक छोटी सी चीज़ को पूरा करने के लिए क्यों चाहते हैं?

+0

आप सही हैं, कोड केवल विचार को प्रदर्शित करना चाहिए, लेकिन यह अमान्य था (सी ++ 0x के साथ मैं सीधे 'स्थैतिक कॉन्स char * s = ...;' संरचना के अंदर लिखा था)। मैं उपरोक्त कोड को सही कर दूंगा। फिर भी, मैं नहीं देखता कि स्ट्रिंग को कैसे प्रारंभ करें (और मेरे प्रश्न का उत्तर दें)! – Thomas

+0

@ थॉमस: '=' के बाद आप कोई फ़ंक्शन कॉल लिख सकते हैं। यह आपके मूल प्रश्न का उत्तर देता है। टिप्पणियों में बाद में आपके द्वारा उठाए गए अतिरिक्त प्रश्न, संकलन समय पर इसे कैसे करें, थोड़ा और मुश्किल है (यदि यह संभव है), लेकिन फिर ऐसा करने के लिए आपकी प्रेरणा 'const' के बारे में अमान्य धारणा पर आधारित है संकलन समय मूल्यांकन की आवश्यकता है। इसलिए, यह हल करने के लिए वास्तविक समस्या पर ध्यान केंद्रित करने में मदद करता है (जिसे आपने भी उल्लेख नहीं किया है), अस्पष्ट रूप से कथित प्रयास किए गए समाधान की अस्पष्ट और गलत रूप से कथित समस्याएं नहीं। चीयर्स और एचटी।, –

+0

@ एएलएफ: आप फ़ंक्शन स्ट्रिंग आवंटित करने के लिए फ़ंक्शन की अपेक्षा करते हैं? ढेर में या ढेर में? – Vlad

5

यह तकनीकी रूप से संभव है, यह बहुत ही बदसूरत है। यहां एक नमूना है जो एक हस्ताक्षरित int के लिए एक स्ट्रिंग अक्षर बनाता है। यह (1) 3 "i-1" फ़ॉर्म की एक स्ट्रिंग नहीं बनाता है, हालांकि मुझे यकीन है कि यदि आप प्रयास करने के इच्छुक हैं तो यह संभव है।

#include <iostream> 
#include <string> 
#include <limits> 

/////////////////////////////////////////////////////////////////////////////// 
// exponentiation calculations 
template <int accum, int base, int exp> struct POWER_CORE : POWER_CORE<accum * base, base, exp - 1>{}; 

template <int accum, int base> 
struct POWER_CORE<accum, base, 0> 
{ 
    enum : int { val = accum }; 
}; 

template <int base, int exp> struct POWER : POWER_CORE<1, base, exp>{}; 

/////////////////////////////////////////////////////////////////////////////// 
// # of digit calculations 
template <int depth, unsigned int i> struct NUM_DIGITS_CORE : NUM_DIGITS_CORE<depth + 1, i/10>{}; 

template <int depth> 
struct NUM_DIGITS_CORE<depth, 0> 
{ 
    enum : int { val = depth}; 
}; 

template <int i> struct NUM_DIGITS : NUM_DIGITS_CORE<0, i>{}; 

template <> 
struct NUM_DIGITS<0> 
{ 
    enum : int { val = 1 }; 
}; 

/////////////////////////////////////////////////////////////////////////////// 
// Convert digit to character (1 -> '1') 
template <int i> 
struct DIGIT_TO_CHAR 
{ 
    enum : char{ val = i + 48 }; 
}; 

/////////////////////////////////////////////////////////////////////////////// 
// Find the digit at a given offset into a number of the form 0000000017 
template <unsigned int i, int place> // place -> [0 .. 10] 
struct DIGIT_AT 
{ 
    enum : char{ val = (i/POWER<10, place>::val) % 10 }; 
}; 

struct NULL_CHAR 
{ 
    enum : char{ val = '\0' }; 
}; 

/////////////////////////////////////////////////////////////////////////////// 
// Convert the digit at a given offset into a number of the form '0000000017' to a character 
template <unsigned int i, int place> // place -> [0 .. 9] 
    struct ALT_CHAR : DIGIT_TO_CHAR< DIGIT_AT<i, place>::val >{}; 

/////////////////////////////////////////////////////////////////////////////// 
// Convert the digit at a given offset into a number of the form '17' to a character 

// Template description, with specialization to generate null characters for out of range offsets 
template <unsigned int i, int offset, int numDigits, bool inRange> 
    struct OFFSET_CHAR_CORE_CHECKED{}; 
template <unsigned int i, int offset, int numDigits>     
    struct OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, false> : NULL_CHAR{}; 
template <unsigned int i, int offset, int numDigits>     
    struct OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, true> : ALT_CHAR<i, (numDigits - offset) - 1 >{}; 

// Perform the range check and pass it on 
template <unsigned int i, int offset, int numDigits> 
    struct OFFSET_CHAR_CORE : OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, offset < numDigits>{}; 

// Calc the number of digits and pass it on 
template <unsigned int i, int offset> 
    struct OFFSET_CHAR : OFFSET_CHAR_CORE<i, offset, NUM_DIGITS<i>::val>{}; 

/////////////////////////////////////////////////////////////////////////////// 
// Integer to char* template. Works on unsigned ints. 
template <unsigned int i> 
struct IntToStr 
{ 
    const static char str[]; 
}; 

template <unsigned int i> 
const char IntToStr<i>::str[] = 
{ 
    OFFSET_CHAR<i, 0>::val, 
    OFFSET_CHAR<i, 1>::val, 
    OFFSET_CHAR<i, 2>::val, 
    OFFSET_CHAR<i, 3>::val, 
    OFFSET_CHAR<i, 4>::val, 
    OFFSET_CHAR<i, 5>::val, 
    OFFSET_CHAR<i, 6>::val, 
    OFFSET_CHAR<i, 7>::val, 
    OFFSET_CHAR<i, 8>::val, 
    OFFSET_CHAR<i, 9>::val, 
    NULL_CHAR::val 
}; 


/////////////////////////////////////////////////////////////////////////////// 
// Tests 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::wcout << IntToStr<17>::str << std::endl; 
    std::wcout << IntToStr<173457>::str << std::endl; 
    std::wcout << IntToStr<INT_MAX>::str << std::endl; 
    std::wcout << IntToStr<0>::str << std::endl; 
    std::wcout << IntToStr<1>::str << std::endl; 
    std::wcout << IntToStr<-1>::str << std::endl; 

    return 0; 
} 
+0

ओपी की समस्या आकार के साथ एक सरणी के लिए कॉल करती है जो टेम्पलेट तर्क मान के कम से कम आनुपातिक है। मुझे लगता है कि स्थैतिक init चरण (हालांकि गतिशील init चरण में मामूली) पर पोर्टेबल मानक सी ++ में करना असंभव है। लेकिन मैं गलत हो सकता था ... :-) चीयर्स, –

+0

@ सीएफ + 0x में एएलएफ स्थिर इनिट चरण के लिए करना मुश्किल है। बहुत बुरा हम अभी भी 2010 में हैं! –

1

मैं लगता है कि यह variadic टेम्पलेट के साथ संभव हो सकता है। मेरे पास परीक्षण करने के लिए एक कंपाइलर नहीं है, लेकिन मैं इस की लाइनों के साथ कुछ अनुमान लगा सकता हूं काम।

template < char ... RHS, unsigned int i> 
struct t { 
    static const char s[] = t<' ', char(i+'0'), RHS, i-1>::s; 
}; 

template <char ... RHS > 
struct t<RHS, 0> { 
    static const char s[] = {'0', RHS, '\0'}; 
}; 

void main() { 
    std::cout << t<5>::s; // {'0',' ','1',' ','2',' ','3',' ','4',' ','5','\0'} 
}