2013-08-03 13 views
7

के रूप में स्ट्रिंग अक्षर को पारित करने का प्रयास कर रहा हूं मैं स्ट्रिंग अक्षर को टेम्पलेट तर्कों के रूप में पास करने का एक आरामदायक तरीका खोजने का प्रयास कर रहा हूं। मैं कंपाइलरों की सबसे व्यापक संख्या का समर्थन करने की परवाह नहीं कर रहा हूं, मैंके साथ जी ++ के नवीनतम संस्करण का उपयोग कर रहा हूं।टेम्पलेट तर्क

मैंने कई संभावित समाधानों की कोशिश की है लेकिन सभी ने मुझे निराश किया है। मैं छोड़ने की तरह हूं, लेकिन पहले मैं क्यों जानना चाहता हूं उनमें से कुछ विफल हो गए।

यहाँ वे हैं:

#include <iostream> 
#include <string> 

using namespace std; 

struct String { 
    char const *m_sz; 

    constexpr String(char const *a_sz) 
     : 
    m_sz(a_sz) {} 

    char const *operator()() const { 
     return m_sz; 
    } 
}; 

template<class _rstr> 
string const Get() { 
    return _rstr(); 
} 

int main() { 
    cout << Get<String("hello")>() << endl; 
    return 0; 
} 

और:

#include <iostream> 
#include <string> 

using namespace std; 

struct String { 
    char const *m_sz; 

    constexpr String(char const *a_sz) 
     : 
    m_sz(a_sz) {} 
}; 

template<String const &_rstr> 
string const Get() { 
    return _rstr.m_sz; 
} 

int main() { 
    String constexpr str = "hello"; 
    cout << Get<str>() << endl; 
    return 0; 
} 

लक्ष्य एक आरामदायक रास्ता एक स्ट्रिंग बेकार प्राप्त समारोह है, जो एक के रूप में अपनी टेम्पलेट तर्क देता है के लिए शाब्दिक पारित करने के लिए खोजने के लिए था std :: स्ट्रिंग ऑब्जेक्ट।

संपादित करें: क्षमा करें, शायद मेरा मुख्य प्रश्न स्पष्ट नहीं है। मेरा सवाल है: उन दो स्निपेट क्यों विफल हो जाते हैं?

+1

पहले मामले में, 'स्ट्रिंग (" हैलो ")': यह एक शॉर्ट सर्किट का इस्तेमाल कर रही STRING_LITERAL घोषणा (C++ 17) से स्ट्रिंग आकार से छुटकारा पाने के है एक मान है, एक प्रकार नहीं, इसलिए इसे टेम्पलेट 'पास <>' पर पास नहीं किया जा सकता है, जो किसी प्रकार की अपेक्षा करता है। दूसरे मामले में, सी ++ 11 मनमाने ढंग से उपयोगकर्ता परिभाषित प्रकारों (जैसे 'स्ट्रिंग') को टेम्पलेट पैरामीटर होने की अनुमति नहीं देता है। –

उत्तर

3

पुन: अपने ओपी: I'd like to know why a couple of them failed.

टिप्पणी @NatanReed से सही है:

  • आपका पहला टुकड़ा में विफल रहता है क्योंकि Get एक TYPE की जरूरत है और एक object दिया जाता है।
  • आपका दूसरा स्निपेट विफल रहता है क्योंकि किसी ऑब्जेक्ट के संदर्भ में टेम्पलेट तर्क को परिभाषित करना अवैध है।
    • सी ++ 2003 तक, जो है। फिर कानूनी बन गया।

खाका तर्क प्रकार के सीमित समूह द्वारा स्थिरांक होना चाहिए।

  • देखें: आईएसओ/आईईसी 14,882-2003 §14.1: टेम्पलेट मापदंडों
  • देखें: आईएसओ/आईईसी 14,882-2003 §14.3.2: खाका गैर-प्रकार तर्क

और फिर भी, String constexpr str = "hello"; में बाहरी संबंध होना चाहिए। तो इसे main() के अंदर ढेर पर डालना काम नहीं करेगा।

#include <iostream> 
#include <string> 

using namespace std; 

struct String { 
    char const *m_sz; 

    constexpr String(char const *a_sz) 
     : 
    m_sz(a_sz) {} 
}; 

template<String const &_rstr> 
string const Get() { 
    return _rstr.m_sz; 
} 

extern String constexpr globally_visible_str = "hello"; 
int main() { 
    cout << Get<globally_visible_str>() << endl; 
    return 0; 
} 
13

के लिए आप टेम्पलेट तर्क के रूप में स्ट्रिंग अक्षर का उपयोग नहीं कर सकते हैं, यह स्पष्ट कारण है कि यह निर्दिष्ट नहीं है कि के दो उदाहरण एक ही वस्तु के साथ शाब्दिक हैं या नहीं। अन्य शब्दों में, दिए गए:

template <char const* str> 
class TC {}; 

TC< "xyz" > v1; 
TC< "xyz" > v2; 

यह अनिर्दिष्ट होगा कि क्या v1 और v2 एक ही प्रकार या नहीं था।

आप char const[] चर टेम्पलेट तर्क के रूप में, तथापि उपयोग कर सकते हैं, क्योंकि वे एक परिभाषित पता है:

template <char const* str> 
class TC {}; 

extern char const xyz[] = "xyz"; 
TC<xyz> v1; 
TC<xyz> v2; 

इस मामले में, v1 और v2 ही प्रकार की गारंटी है।

संपादित करें:

मैं सी ++ 11 स्ट्रिंग के परिभाषा पर extern के लिए की जरूरत निकाल देता है, कम से कम अगर स्ट्रिंग और इन्स्टेन्शियशन सभी एक ही अनुवाद इकाई में हैं लगता है। मैं निश्चित नहीं हूं, हालांकि; एक बार मैंने ऐसा कुछ किया, मैंने को सी ++ 11 तक पहुंच नहीं दी।

+0

मैं पुष्टि कर सकता हूं कि 'बाहरी' की सीमा हटा दी गई थी क्योंकि मैंने इसके बिना प्रयास किया है और यह काम करता है (यह मेरे कई प्रयासों में से एक था)। इसके अलावा, मुझे पता है कि मैं स्ट्रिंग अक्षर सीधे पास नहीं कर सकता लेकिन मैं इसे किसी तरह से रोकने की कोशिश कर रहा था, और शायद असफल रहा। –

+0

स्पष्टीकरण: बाह्य लिंक (आमतौर पर एक वैश्विक) के साथ एक चर घोषित करना मेरे लिए "आरामदायक" नहीं है।कुछ प्रकार के 'स्ट्रिंग' एडाप्टर का उपयोग करने में सक्षम होने के नाते, जैसे कि मेरे दो स्निपेट में, अधिक आरामदायक है। –

5

आप "अनुकरण" कर सकते हैं सी ++ 11 variadic टेम्पलेट के साथ तार:

यह प्रिंट:

हैलो दुनिया !!!

+0

हां, मैंने कोशिश की है और यह काम करता है लेकिन यह भी आरामदायक नहीं है। वैसे भी, मेरा मुख्य सवाल यह है: मैं दो स्निपेट क्यों पोस्ट नहीं करूंगा? –

5

मैं जानता हूँ कि पोस्ट पुरानी है, लेकिन मैं इस समस्या के लिए किसी भी समाधान यहाँ नहीं मिला है, और हो सकता है कि किसी ने मेरे वैकल्पिक हल में रुचि होगी:

template <int N> 
constexpr int string_literal_length(const char (&str)[N]) { 
    return N - 1; 
} 

template <int PassedLength, int CountedLength, char... Characters> 
struct string_literal { 
    static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string..."); 
}; 

#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)> 

// ... as long as we need it ... 
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127] 
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126] 
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125] 
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124] 
// ... 
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4] 
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3] 
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2] 
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1] 
#define STRING_LITERAL_1(str) str[0] 

इस आज़मा कर देखें

अब उपयोग:

template <class SLiteral> 
struct usage_of_string_literal { 
}; 

int main() { 
    usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl; 
} 

दुर्भाग्य से एक यह काम पाने के लिए स्ट्रिंग की लंबाई प्रदान करने के लिए है, लेकिन यह अभी भी वर्ण के मैदान variadic आर्ग टेम्पलेट तुलना में अधिक आरामदायक समाधान है, और लंबाई static_assert द्वारा सत्यापित किया जाता तो संकलक उचित मान लेने के लिए मदद कर सकते हैं ...


संपादित

एक और टेम्पलेट जादू।

#include <type_traits> 
#include <utility> 

#define MAX_STRING_LITERAL_LENGTH 11 
#define STRING_LITERAL(str) string_literal<char_pack<STRING_LITERAL_11(str)>>::s 

#define STRING_LITERAL_11(str) STRING_LITERAL_10(str), ((TERMINATED_10(str))?(str[10]):('\0')) 
#define STRING_LITERAL_10(str) STRING_LITERAL_9(str), ((TERMINATED_9(str))?(str[9]):('\0')) 
#define STRING_LITERAL_9(str) STRING_LITERAL_8(str), ((TERMINATED_8(str))?(str[8]):('\0')) 
#define STRING_LITERAL_8(str) STRING_LITERAL_7(str), ((TERMINATED_7(str))?(str[7]):('\0')) 
#define STRING_LITERAL_7(str) STRING_LITERAL_6(str), ((TERMINATED_6(str))?(str[6]):('\0')) 
#define STRING_LITERAL_6(str) STRING_LITERAL_5(str), ((TERMINATED_5(str))?(str[5]):('\0')) 
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), ((TERMINATED_4(str))?(str[4]):('\0')) 
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), ((TERMINATED_3(str))?(str[3]):('\0')) 
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), ((TERMINATED_2(str))?(str[2]):('\0')) 
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), ((TERMINATED_1(str))?(str[1]):('\0')) 
#define STRING_LITERAL_1(str) str[0] 


#define TERMINATED_10(str) TERMINATED_9(str) && str[9] 
#define TERMINATED_9(str) TERMINATED_8(str) && str[8] 
#define TERMINATED_8(str) TERMINATED_7(str) && str[7] 
#define TERMINATED_7(str) TERMINATED_6(str) && str[6] 
#define TERMINATED_6(str) TERMINATED_5(str) && str[5] 
#define TERMINATED_5(str) TERMINATED_4(str) && str[4] 
#define TERMINATED_4(str) TERMINATED_3(str) && str[3] 
#define TERMINATED_3(str) TERMINATED_2(str) && str[2] 
#define TERMINATED_2(str) TERMINATED_1(str) && str[1] 
#define TERMINATED_1(str) str[0] 

template <char... Cs> 
struct char_pack { 
    static constexpr char const arr[sizeof...(Cs) + 1] = {Cs..., 0}; 
    static constexpr std::size_t non_zero_count = (((Cs != 0)?1:0) + ...); 
    static_assert(non_zero_count < MAX_STRING_LITERAL_LENGTH, "You need to create more macros"); 
}; 

template <char... Cs> 
constexpr char const char_pack<Cs...>::arr[sizeof...(Cs) + 1]; 

template <char... Cs> 
constexpr std::size_t char_pack<Cs...>::non_zero_count; 

template <class CP, class = void, class = std::make_index_sequence<CP::non_zero_count>> 
struct string_literal; 

template <char... Cs, std::size_t... Is> 
struct string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>> { 
    static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'}; 
}; 

template <char... Cs, std::size_t... Is> 
constexpr char const string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>>::s[sizeof...(Cs) + 1]; 

template <char... Cs, std::size_t... Is> 
struct string_literal<char_pack<Cs...>, std::enable_if_t<!(Cs && ...)>, std::index_sequence<Is...>>: string_literal<char_pack<char_pack<Cs...>::arr[Is]...>> { }; 

template <const char *> 
struct foo {}; 

int main() { 
    foo<STRING_LITERAL("abcdefghij")> f; 
    static_cast<void>(f); 
} 

[live demo]

+0

मुझे लगता है कि लम्बाई गुजरने के लिए अभी तक एक और संकेतक मैक्रो होने से हटाया जा सकता है .. '#define STRING_LITERAL_ (STR) STRING_LITERAL (आकार (एसटीआर) - 1, एसटीआर)'। उपयोग: 'STRING_LITERAL _ (" 123456789012 ")'। बीटीडब्ल्यू, [इस उत्तर] में वर्णित एक बूस्ट सुविधा भी है (http://stackoverflow.com/a/18154638/514235)। हालांकि, आपका जवाब अच्छा है कि यह रेडीमेड समाधान प्रदान करता है। आप 'class string_literal' के अंदर 'कॉन्स्ट char'' सरणी भी डाल सकते हैं जो सभी व्यक्तिगत वर्णों को फिर से स्ट्रिंग में याद कर देगा। – iammilind

+1

अपना कोड सत्यापित करें और ऐसा लगता है कि आपने जो भी किया है वह सही है; यानी हम इस कोड के काम के लिए एक शाब्दिक संख्या के रूप में लंबाई को स्पष्ट रूप से पारित करने की आवश्यकता है। मैं इस धारणा के तहत था कि, आपने बढ़ावा देने के तरीके को लागू किया है 'एमपीएलआईबीएस_स्ट्रिंग' लागू किया गया है। ऐसा लगता है कि उस मैक्रो के लिए काम करने के लिए कुछ जटिल चालबाजी होनी चाहिए। – iammilind

+0

@iammilind मैंने 'BOOST_HANA_STRING' के बारे में सुना लेकिन जहां तक ​​मुझे पता है कि इसका उपयोग असंबद्ध संदर्भ में नहीं किया जा सकता है क्योंकि यह लैम्बडास का उपयोग करता है ... मैं 'एमपीएलआईबीएस_स्ट्रिंग' देखता हूं। लंबाई के लिए इसे 'आकार' के साथ आदान-प्रदान नहीं किया जा सकता है क्योंकि मैंने सरल एक्स्टेंसिबल लूप करने के लिए कॉन्सटेनेशन का उपयोग किया था, शायद उन्होंने कुछ और जटिल प्रीप्रोसेसर पाश तंत्र का उपयोग किया ... –

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