Macro for static std::string object from literal

前端 未结 5 2174
萌比男神i
萌比男神i 2021-02-12 17:56

Suppose I need to call a function foo that takes a const std::string reference from a great number of places in my code:

int foo(const          


        
相关标签:
5条回答
  • 2021-02-12 18:13

    You could use Boost.Flyweight to make a key-value flyweight from const char* to std::string. I'm not sure about the details, might be that it is enough to use flyweight<std::string> everywhere.

    0 讨论(0)
  • 2021-02-12 18:16

    This will work for simple strings - w/o whitespace:

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

    Usage in header (parse once!):

    DECL_STR(Foo);
    DECL_STR(Bar);
    

    In code:

    func(str_Foo);
    func(str_Bar);
    
    0 讨论(0)
  • 2021-02-12 18:21

    If you can use boost 1.55 or greater you can do

    #include <boost/utility/string_ref.hpp>
    
    void foo(const boost::string_ref& xyz)
    {
    }
    
    0 讨论(0)
  • 2021-02-12 18:22

    You may use something like to create your static std::string "in place":

    #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

    0 讨论(0)
  • 2021-02-12 18:23

    If that function foo does not make a copy of the string then its interface is sub-optimal. It is better to change it to accept char const* or string_view, so that the caller is not required to construct std::string.

    Or add overloads:

    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 讨论(0)
提交回复
热议问题