c++type-conversionc++20user-defined-literals

Convert const char* to const char_type* at compile time


Consider the following code:

using char_type = /*implementation defined*/;

void foo(const char_type*);

int main()
{
    foo("Hello World!");
}

The string literal "Hello World!" is a const char* that, depending on the implementation, may not be convertible to const char_type*. I want my code to be portable between different implementations so I thought I could define a literal to convert one char after another (this type of conversion is guaranteed to work):

consteval const char_type* operator"" _s(const char*, size_t);

and then use it like this foo("Hello World!"_s). However, the only implementation I can think of uses new to allocate space and std::copy but that would be extremely slow. I want to make the conversion at compile time and luckily I can use c++20 and the consteval keyword to ensure that the call to the function always produces a contant expression (user defined literals are still normal functions, they can be called at runtime). Any idea how to implement this?


Solution

  • This conversion is possible through a two-step process: first, by declaring a class that can convert a const char * to a char_type array within a compile-time constructor; second, by using that class within a user-defined literal:

    #include <algorithm>
    
    template<std::size_t N>
    struct string_convert {
        char_type str[N] = {};
    
        consteval string_convert(const char (&s)[N]) {
            std::copy(s, s + N, str);
        }
    };
    
    template<string_convert SC>
    consteval auto operator ""_s()
    {
        return SC.str;
    }
    

    This interface allows for the following use:

    void foo(const char_type *s);
    
    foo("Hello, world!"_s);
    

    Try it on Godbolt. Note that neither string_convert nor the user-defined literal appear in the disassembly; all that remains is the converted array.