介绍:
由于VS2019中启用了char8_t,decltype(u8"字符串") 是 const char8_t(&)[ N ],导致许多代码需要变更。
然而一旦变更后,回到VS2017中反而会因为重载和模板匹配的问题导致错误,这就需要一些兼容机制来处理移植问题。
一个是https://github.com/tahonermann/char8_t-remediation。用法不太清楚。
下面介绍一下我编写的UTF8Compatible.h
可用于VS2017~VS2019之间,其他编译器暂未实验相信改的不多。至于不支持u8""的低版本编译器本就不考虑在内了。
#pragma once
#ifndef _H_UTF8_H_
#define _H_UTF8_H_
#include <string>
#include <type_traits>
using namespace std::literals;
#if !defined(__cpp_char8_t)
using char8_t = unsigned char;
namespace std
{
using u8string = std::basic_string<char8_t, char_traits<char8_t>, allocator<char8_t>>;
using u8string_view = std::basic_string_view<char8_t>;
}
template<typename T> struct StringLiteralHelp;
template<int N> struct StringLiteralHelp<const char(&)[N]>
{
using type = const char8_t(&)[N];
};
template<> struct StringLiteralHelp<char>
{
using type = char8_t;
};
//用于传参与赋值指针
#define U8(x) ((StringLiteralHelp<decltype(u8##x)>::type)(u8##x))
//原始的字符串形式,用于构造数组
#define U8c(x) (u8##x)
_NODISCARD inline std::u8string operator "" ___u8s(const char* _Str, size_t _Len)
{
return (std::u8string((const char8_t*)_Str, _Len));
}
#define U8S(x) (u8##x##___u8s)
#else
#define U8(x) (u8##x) //用于传参与赋值指针,或赋值给auto 、auto&、auto*、const char8_t*、赋值。同样可用于字符 U8('中')
#define U8c(x) (u8##x) //原始的字符串形式,唯一用途是用于给数组初始化 char8_t s[N] = U8c("xxxx")、char8_t s[] = U8c("xxxx")
#define U8S(x) (u8##x##s) //构造一个u8string
#endif
#endif //_H_UTF8_H_
附带u8string和 u8string_view的可视化 UTF8Compatible.natvis
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="std::basic_string<unsigned char,*>">
<Intrinsic Name="size" Expression="_Mypair._Myval2._Mysize" />
<Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myres" />
<!-- _BUF_SIZE = 16 / sizeof(char) < 1 ? 1 : 16 / sizeof(char) == 16 -->
<Intrinsic Name="bufSize" Expression="16" />
<Intrinsic Name="isShortString" Expression="capacity() < bufSize()" />
<Intrinsic Name="isLongString" Expression="capacity() >= bufSize()" />
<DisplayString Condition="isShortString()">{_Mypair._Myval2._Bx._Buf,s8}</DisplayString>
<DisplayString Condition="isLongString()">{_Mypair._Myval2._Bx._Ptr,s8}</DisplayString>
<StringView Condition="isShortString()">_Mypair._Myval2._Bx._Buf,s8</StringView>
<StringView Condition="isLongString()">_Mypair._Myval2._Bx._Ptr,s8</StringView>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<Item Name="[capacity]" ExcludeView="simple">capacity()</Item>
<Item Name="[allocator]" ExcludeView="simple">_Mypair</Item>
<ArrayItems>
<Size>_Mypair._Myval2._Mysize</Size>
<ValuePointer Condition="isShortString()">_Mypair._Myval2._Bx._Buf</ValuePointer>
<ValuePointer Condition="isLongString()">_Mypair._Myval2._Bx._Ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="std::basic_string<signed char,*>">
<Intrinsic Name="size" Expression="_Mypair._Myval2._Mysize" />
<Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myres" />
<!-- _BUF_SIZE = 16 / sizeof(char) < 1 ? 1 : 16 / sizeof(char) == 16 -->
<Intrinsic Name="bufSize" Expression="16" />
<Intrinsic Name="isShortString" Expression="capacity() < bufSize()" />
<Intrinsic Name="isLongString" Expression="capacity() >= bufSize()" />
<DisplayString Condition="isShortString()">{_Mypair._Myval2._Bx._Buf,s8}</DisplayString>
<DisplayString Condition="isLongString()">{_Mypair._Myval2._Bx._Ptr,s8}</DisplayString>
<StringView Condition="isShortString()">_Mypair._Myval2._Bx._Buf,s8</StringView>
<StringView Condition="isLongString()">_Mypair._Myval2._Bx._Ptr,s8</StringView>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<Item Name="[capacity]" ExcludeView="simple">capacity()</Item>
<Item Name="[allocator]" ExcludeView="simple">_Mypair</Item>
<ArrayItems>
<Size>_Mypair._Myval2._Mysize</Size>
<ValuePointer Condition="isShortString()">_Mypair._Myval2._Bx._Buf</ValuePointer>
<ValuePointer Condition="isLongString()">_Mypair._Myval2._Bx._Ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="std::basic_string_view<unsigned char,*>">
<Intrinsic Name="size" Expression="_Mysize" />
<Intrinsic Name="data" Expression="_Mydata" />
<DisplayString>{_Mydata,[_Mysize]s8}</DisplayString>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<ArrayItems>
<Size>size()</Size>
<ValuePointer>data()</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="std::basic_string_view<signed char,*>">
<Intrinsic Name="size" Expression="_Mysize" />
<Intrinsic Name="data" Expression="_Mydata" />
<DisplayString>{_Mydata,[_Mysize]s8}</DisplayString>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<ArrayItems>
<Size>size()</Size>
<ValuePointer>data()</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>