(); std::wcout <<" /> (); std::wcout <<" /> (); std::wcout <<"/>

How to create a string literal based on generic character type in c++20?

45 views Asked by At

Given the following test case

int main(int argc, char const* argv[]) {
    {
        constexpr wchar_t const* v = gstring<"hello world", wchar_t>();
        std::wcout << v << std::endl;
        std::wcout << std::wcslen(v) << std::endl;
    }
    {
        constexpr char const* v = gstring<L"world hello", char>();
        std::wcout << v <<  std::endl;
        std::wcout << std::strlen(v) << std::endl;
    }
    return 0;
}

the output should be

hello world
11
world hello
11

This is useful when the character type is passed in as a type parameter. For example

template <typename TChar>
void AddFoo(std::basic_string<TChar> & s){
    s.Append( gstring<"foo", TChar>() );
}
1

There are 1 answers

0
bradgonesurfing On
#include <cstring>
#include <iostream>
#include <string>

template <typename Char, unsigned N>
struct Capture {
    Char string_[N + 1]{};

    template <typename TChar>
    consteval Capture(TChar const* string) {
        for (unsigned index = 0; index < N+1; ++index) {
            string_[index] = string[index];
        }
    }

    template <typename TChar> 
    consteval auto As() const{
        return Capture<TChar, N>(string_);
    }
};

template <typename TChar, unsigned N>
Capture(TChar const (&)[N]) -> Capture<TChar, N - 1>;

template <Capture string, typename Char, auto cast = string.template As<Char>()>
consteval auto gstring() {
    return cast.string_;
}


It requires a two stage process. The first step is to capture the const char * using an implicit conversion to type Capture. The second step is to call the As method on Capture to convert the buffer to the new type. All this is done consteval and via template parameters to ensure that the literal object is global.

The gstring method can return the inner final buffer as cast.string_ because cast is a template parameter and thus a compile time constant.

See the solution on GodBolt https://godbolt.org/z/GaTnh69cM

Note: The conversion should really only be used from char -> char or char -> wchar_t. Obviously not all values in wchar have values in char