2014-09-09 9 views
18

से स्ट्रिंग वस्तु मान लीजिए मैं एक समारोह foo कि मेरे कोड में स्थानों की एक बड़ी संख्या में से एक स्थिरांक std::string संदर्भ लेता कॉल करने की आवश्यकता:मैक्रो :: शाब्दिक

int foo(const std::string&); 
.. 
foo("bar"); 
.. 
foo("baz"); 

एक तार के साथ एक समारोह कॉलिंग इस तरह के शाब्दिक std::string ऑब्जेक्ट्स बनाते हैं, प्रत्येक बार शाब्दिक प्रतिलिपि बनाते हैं।

जब तक मैं गलत नहीं हूं, संकलक प्रति स्थिर std::string ऑब्जेक्ट प्रति शाब्दिक बनाकर इसे अनुकूलित नहीं करेंगे जिसे बाद में कॉल के लिए पुन: उपयोग किया जा सकता है। मुझे पता है कि g ++ में उन्नत स्ट्रिंग पूल तंत्र हैं, लेकिन मुझे नहीं लगता कि यह std::string ऑब्जेक्ट्स स्वयं तक फैली हुई है।

static std::string bar_string("bar"); 
foo(bar_string); 
.. 
static std::string baz_string("baz"); 
foo(baz_string); 

Callgrind का उपयोग करना, मैं पुष्टि कर सकता कि यह वास्तव में मेरा कार्यक्रम में तेजी लाने करता है:

मैं इस "अनुकूलन" अपने आप को, जो कोड कुछ हद तक कम पठनीय बनाता कर सकते हैं।

मैंने सोचा कि मैं इसके लिए मैक्रो बनाने की कोशिश करूंगा, लेकिन मुझे नहीं पता कि यह संभव है या नहीं। मैं जो चाहता हूं वह कुछ है:

foo(STATIC_STRING("bar")); 
.. 
foo(STATIC_STRING("baz")); 

मैंने शाब्दिक के साथ टेम्पलेट पैरामीटर के रूप में टेम्पलेट बनाने का प्रयास किया, लेकिन यह असंभव साबित हुआ। और चूंकि कोड ब्लॉक में फ़ंक्शन परिभाषा संभव नहीं है, इसलिए मैं विचारों से बाहर हूं।

क्या ऐसा करने का एक शानदार तरीका है, या मुझे कम पठनीय समाधान का सहारा लेना होगा?

+3

char * के बजाय उपयोग कर सकते हैं? – ZivS

+0

तो, '[]() -> std :: स्ट्रिंग कॉन्स और {std :: स्ट्रिंग कॉन्स एस (" बार ") के बारे में क्या; वापसी एस; }() '? – dyp

+0

सी ++ 14 के साथ, आप उपयोगकर्ता द्वारा परिभाषित शाब्दिक '" बार "एस का उपयोग कर सकते हैं, लेकिन मुझे यकीन नहीं है कि यह एक प्रतिलिपि बनाता है या नहीं –

उत्तर

6

आप "स्थान पर" अपने static std::stringबनाने के लिए की तरह कुछ का उपयोग हो सकता है:

#include <cstdint> 
#include <string> 

// Sequence of char 
template <char...Cs> struct char_sequence 
{ 
    template <char C> using push_back = char_sequence<Cs..., C>; 
}; 

// Remove all chars from char_sequence from '\0' 
template <typename, char...> struct strip_sequence; 

template <char...Cs> 
struct strip_sequence<char_sequence<>, Cs...> 
{ 
    using type = char_sequence<Cs...>; 
}; 

template <char...Cs, char...Cs2> 
struct strip_sequence<char_sequence<'\0', Cs...>, Cs2...> 
{ 
    using type = char_sequence<Cs2...>; 
}; 

template <char...Cs, char C, char...Cs2> 
struct strip_sequence<char_sequence<C, Cs...>, Cs2...> 
{ 
    using type = typename strip_sequence<char_sequence<Cs...>, Cs2..., C>::type; 
}; 

// struct to create a std::string 
template <typename chars> struct static_string; 

template <char...Cs> 
struct static_string<char_sequence<Cs...>> 
{ 
    static const std::string str; 
}; 

template <char...Cs> 
const 
std::string static_string<char_sequence<Cs...>>::str = {Cs...}; 

// helper to get the i_th character (`\0` for out of bound) 
template <std::size_t I, std::size_t N> 
constexpr char at(const char (&a)[N]) { return I < N ? a[I] : '\0'; } 

// helper to check if the c-string will not be truncated 
template <std::size_t max_size, std::size_t N> 
constexpr bool check_size(const char (&)[N]) 
{ 
    static_assert(N <= max_size, "string too long"); 
    return N <= max_size; 
} 

// Helper macros to build char_sequence from c-string 
#define PUSH_BACK_8(S, I) \ 
    ::push_back<at<(I) + 0>(S)>::push_back<at<(I) + 1>(S)> \ 
    ::push_back<at<(I) + 2>(S)>::push_back<at<(I) + 3>(S)> \ 
    ::push_back<at<(I) + 4>(S)>::push_back<at<(I) + 5>(S)> \ 
    ::push_back<at<(I) + 6>(S)>::push_back<at<(I) + 7>(S)> 

#define PUSH_BACK_32(S, I) \ 
     PUSH_BACK_8(S, (I) + 0) PUSH_BACK_8(S, (I) + 8) \ 
     PUSH_BACK_8(S, (I) + 16) PUSH_BACK_8(S, (I) + 24) 

#define PUSH_BACK_128(S, I) \ 
    PUSH_BACK_32(S, (I) + 0) PUSH_BACK_32(S, (I) + 32) \ 
    PUSH_BACK_32(S, (I) + 64) PUSH_BACK_32(S, (I) + 96) 

// Macro to create char_sequence from c-string (limited to 128 chars) without leading '\0' 
#define MAKE_CHAR_SEQUENCE(S) \ 
    strip_sequence<char_sequence<> \ 
    PUSH_BACK_128(S, 0) \ 
    ::push_back<check_size<128>(S) ? '\0' : '\0'> \ 
    >::type 

// Macro to return an static std::string 
#define STATIC_STRING(S) static_string<MAKE_CHAR_SEQUENCE(S)>::str 

Live example

+1

कमाल! केवल नकारात्मक पक्ष यह है कि यह कुछ C++ 11 वाक्यविन्यास का उपयोग करता है जो g ++ 4.4 में उपलब्ध नहीं है। 4.8 के साथ यह पूरी तरह से काम करता है, हालांकि। – Masseman

10

यदि यह कार्य foo स्ट्रिंग की एक प्रति नहीं बनाता है तो इसका इंटरफ़ेस उप-इष्टतम है। char const* या string_view को स्वीकार करने के लिए इसे बेहतर बनाना बेहतर है, ताकि कॉलर को std::string बनाने की आवश्यकता न हो।

या जोड़ने के भार के:

void foo(char const* str, size_t str_len); // Does real work. 

inline void foo(std::string const& s) { foo(s.data(), s.size()); } 
inline void foo(char const* s) { foo(s, strlen(s)); } 
+0

यदि 'foo' स्ट्रिंग की एक प्रति बनाता है, तो इंटरफ़ेस उप- इष्टतम। यदि 'foo' स्ट्रिंग की एक प्रति बनाता है, तो मूल्य से गुजरना बेहतर होता है। –

+1

मैं सहमत हूं। इंटरफ़ेस को अनिवार्य रूप से 'std :: string' की आवश्यकता नहीं होनी चाहिए, लेकिन कभी-कभी इंटरफ़ेस आपके बदलने के लिए नहीं होता है, या स्ट्रिंग ऑब्जेक्ट को वास्तव में 'foo' में रेखा के नीचे की आवश्यकता होती है। – Masseman

+0

@LuchianGrigore True। जीसीसी संदर्भ के लिए 'std :: string' गिनती के संदर्भ में इसे स्वीकार करने के लिए डेटा प्रतियों के संदर्भ में मूल्य के अनुसार उतना ही अच्छा है। –

1

आप Boost.Flyweight का उपयोग std::string को const char* से एक key-value flyweight बनाने के लिए कर सकता है। मुझे विवरण के बारे में निश्चित नहीं है, हो सकता है कि यह हर जगह flyweight<std::string> का उपयोग करने के लिए पर्याप्त है।

1

यह सरल स्ट्रिंग्स के लिए काम करेंगे - डब्ल्यू/खाली स्थान के o:

#define DECL_STR(s) const std::string str_##s (#s) 

शीर्षलेख में उपयोग (एक बार पार्स!):

DECL_STR(Foo); 
DECL_STR(Bar); 

कोड में:

func(str_Foo); 
func(str_Bar); 
+1

ठीक है, यह वास्तव में मेरे "कम पठनीय" समाधान से अधिक पठनीय या कॉम्पैक्ट नहीं है। – Masseman

2

आप बढ़ावा 1 का उपयोग कर सकते हैं।55 या इससे अधिक आप

#include <boost/utility/string_ref.hpp> 

void foo(const boost::string_ref& xyz) 
{ 
} 
संबंधित मुद्दे