VS2019中使用char8_t編程後,代碼兼容2017的方法

介紹:
由於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&lt;unsigned char,*&gt;">
    <Intrinsic Name="size" Expression="_Mypair._Myval2._Mysize" />
    <Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myres" />
    <!-- _BUF_SIZE = 16 / sizeof(char) &lt; 1 ? 1 : 16 / sizeof(char) == 16 -->
    <Intrinsic Name="bufSize" Expression="16" />
    <Intrinsic Name="isShortString" Expression="capacity() &lt; bufSize()" />
    <Intrinsic Name="isLongString" Expression="capacity() &gt;= 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&lt;signed char,*&gt;">
    <Intrinsic Name="size" Expression="_Mypair._Myval2._Mysize" />
    <Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myres" />
    <!-- _BUF_SIZE = 16 / sizeof(char) &lt; 1 ? 1 : 16 / sizeof(char) == 16 -->
    <Intrinsic Name="bufSize" Expression="16" />
    <Intrinsic Name="isShortString" Expression="capacity() &lt; bufSize()" />
    <Intrinsic Name="isLongString" Expression="capacity() &gt;= 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&lt;unsigned char,*&gt;">
    <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&lt;signed char,*&gt;">
    <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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章