How to define string literal with character type that depends on template parameter?

前端 未结 5 1300
不知归路
不知归路 2021-02-06 07:47
template
class StringTraits {
public:
    static const CharType NULL_CHAR = \'\\0\';
    static constexpr CharType* WHITESPACE_STR = \" \";
};

         


        
5条回答
  •  离开以前
    2021-02-06 08:24

    Here is a refinement of the now-common template-based solution which

    • preserves the array[len] C++ type of the C strings rather than decaying them to pointers, which means you can call sizeof() on the result and get the size of the string+NUL, not the size of a pointer, just as if you had the original string there.

    • Works even if the strings in different encodings have different length in code units (which is virtually guaranteed if the strings have non-ASCII text).

    • Does not incur any runtime overhead nor does it attempt/need to do encoding conversion at runtime.

    Credit: This refinement starts with the original template idea from Mark Ransom and #2 from zett42 and borrows some ideas from, but fixes the size limitations of, Chris Kushnir's answer.

    This code does char and wchar_t but it is trivial to extend it to char8_t+char16_t+char32_t

    // generic utility for C++ pre-processor concatenation
    // - avoids a pre-processor issue if x and y have macros inside
    #define _CPP_CONCAT(x, y) x ## y
    #define  CPP_CONCAT(x, y) _CPP_CONCAT(x, y)
    
    // now onto stringlit()
    
    template
    constexpr
    auto  _stringlit(char c,
                     const char     (&s0)  [SZ0],
                     const wchar_t  (&s1)  [SZ1]) -> const char(&)[SZ0] 
    {
        return s0;
    }
    
    template
    constexpr
    auto  _stringlit(wchar_t c,
                     const char     (&s0)  [SZ0],
                     const wchar_t  (&s1)  [SZ1]) -> const wchar_t(&)[SZ1] 
    {
        return s1;
    }
    
    #define stringlit(code_unit, lit) \
        _stringlit(code_unit (), lit, CPP_CONCAT(L, lit))
    

    Here we are not using C++ overloading but rather defining one function per char encoding, each function with different signatures. Each function returns the original array type with the original bounds. The selector that chooses the appropriate function is a single character in the desired encoding (value of that character not important). We cannot use the type itself in a template parameter to select because then we'd be overloading and have conflicting return types. This code also works without the constexpr. Note we are returning a reference to an array (which is possible in C++) not an array (which is not allowed in C++). The use of trailing return type syntax here is optional, but a heck of a lot more readable than the alternative, something like const char (&stringlit(...params here...))[SZ0] ugh.

    I compiled this with clang 9.0.8 and MSVC++ from Visual Studio 2019 16.7 (aka _MSC_VER 1927 aka pdb ver 14.27). I had c++2a/c++latest enabled, but I think C++14 or 17 is sufficient for this code.

    Enjoy!

提交回复
热议问题