介紹:
由於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>