c++templatescharwchar-t

string literal - template conversion between char types


I would like to code a function that would look like:

template <typename CharT>
std::basic_string<CharT> convert(char const *);

and be used as follows:

convert<char>("Hello World!");     //  "Hello World!"
convert<wchar_t>("Hello World!");  // L"Hello World!"
convert<char16_t>("Hello World!"); // u"Hello World!"
convert<char32_t>("Hello World!"); // U"Hello World!"

I could use std::codecvt and co, but I find it almost pointless as it would be so easier to use some macro that adds L, u or U with 0 cost.

Unfortunately templates and macros don't act at the same level... So here comes my question: would there be some way to mix them ? Or is there a better way ?

My main goal is to avoid repetition (specialization) of code: some functions I'm coding are CharT templated and use string literals, and that would be the only difference. As an example:

template <typename CharT>
void foo (std::vector<std::basic_string<CharT>> const & vec, 
          std::basic_string<CharT> str = convert<CharT>("default"));

That would avoid to specialize foo() for each char type.

Many thanks for your help


Solution

  • I finally got the idea of using macros to generate every 4 overloads of the function foo.

    template <typename CharT>
    void foo (std::vector<std::basic_string<CharT>> const & vec, 
              std::basic_string<CharT> str = convert<CharT>("default"));
    

    becomes

    #define FOO(CharT, prefix) \
    void foo (std::vector<std::basic_string<CharT>> const & vec, \
              std::basic_string<CharT> str = prefix ## "default");
    

    and I just have to add

    FOO(char, )
    FOO(wchar_t, L)
    FOO(char16_t, u)
    FOO(char32_t, U)
    

    four lines that I can also put into another macro GENERATE so I can simply call

    GENERATE(FOO)
    

    I know macros... but I've reached my main goal to avoid code repetition. :-)

    Thanks everybody for your help!

    Update

    After reading the paper Formatting Ranges and the mention of "STATICALLY-WIDEN", I finally have:

    template <typename CharT>
    constexpr auto statically_widen(
    #ifdef __cpp_char8_t
        const char8_t * u8str,
    #endif
        const char16_t* u16str,
        const char32_t* u32str,
        const char * str,
        const wchar_t* wstr
    ) {
        if constexpr (std::is_same<CharT, char>::value)
            return str;
        else if constexpr (std::is_same<CharT, wchar_t>::value)
            return wstr;
    #ifdef __cpp_char8_t
        else if constexpr (std::is_same<CharT, char8_t>::value)
            return u8str;
    #endif
        else if constexpr (std::is_same<CharT, char16_t>::value)
            return u16str;
        else if constexpr (std::is_same<CharT, char32_t>::value)
            return u32str;
    }
    
    #ifdef __cpp_char8_t
        #define STATICALLY_WIDEN(CharT, str) statically_widen<CharT>(u8##str, u##str, U##str, str, L##str)
    #else
        #define STATICALLY_WIDEN(CharT, str) statically_widen<CharT>(u##str, U##str, str, L##str)
    #endif
    
    template <typename CharT>
    void foo (std::vector<std::basic_string<CharT>> const & vec, 
              std::basic_string<CharT> str = STATICALLY_WIDEN(CharT, "default"));