0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

マルチプラットフォーム対応の std::string と std::wstring の間の変換を行うライブラリを作るよ

Last updated at Posted at 2022-05-10

マルチバイト文字列(std::string)とワイド文字列(std::wstring)の間の変換を行うライブラリを作りました(SJIS, UTF-8, UTF-16に対応。SJIS⇔UTF-8の変換も可能) の第二弾。

開発中のソースを現在貼り付けて公開中・・・。

総じて、v1系とのソース互換の向上を目指した。

  • Windows/Linux環境下で、strconv.h (v1系) であった全ての文字コード変換関数をサポート。(ansi_to_~()、~_to_ansi() を除く)
  • strconv.h (v1系) であった formatA()関数は廃止、 format()関数がインテリジェントになった。chcpに関係なく韓国語等のユニコード文字を出力できる。formatA() を復活させた。
  • strconv.h (v1系) で unicode_ostream uout(std::cout, GetConsoleOutputCP()); と指定していたのをマルチプラットフォーム対応のため、unicode_ostream uout(std::cout); とした(コードページを指定する第二引数を廃止)。ダミーの第二引数を受け付けるようにして、Linux環境では GetConsoleOutputCP() および GetConsoleCP() が (0) に展開されるようなマクロを用意して v1系とのソース互換を目指した。
  • wchar_t * または std::wstring を直接出力できない仕様とした。utf8(std::string)またはchar8(std::u8string)に変換してから出力する。
  • utf8/char8 と char16(std::u16string)/char32(std::u32string) との間の変換関数を用意した。
  • unicode_ostream が char16(char16_t *, std::u16string) および char32(char32_t *, std::u32string) を受け付けるようにした。
デモソースコード
#include "strconvxp.h"
#include <iomanip>
#include <cmath>

using namespace std;

class CMyClass
{
    time_t t;
    int count;

public:
    CMyClass()
    {
        this->t = std::time(nullptr);
        this->count = 0;
    }
    int CountUp()
    {
        return ++this->count;
    }
    friend unicode_ostream &operator<<(unicode_ostream &stream, const CMyClass &value);
};

unicode_ostream &operator<<(unicode_ostream &stream, const CMyClass &value)
{
    struct tm *ptm = std::localtime(&value.t);
    stream << u8"[作成日時=" << std::put_time(ptm, "%Y-%m-%d %H:%M:%S");
    stream << u8"、カウント=" << value.count << "]";
    return stream;
};

int main(int argc, char *argv[])
{
    // demo 1
    std::string utf8_str = U8("あいう");
    format(cout, "utf8_str.length()=%u\n", utf8_str.length());
    std::wstring wide_str = utf8_to_wide(utf8_str);
    format(cout, "wide_str.length()=%u\n", wide_str.length());
    std::string sjis_str = wide_to_sjis(wide_str);
    format(cout, "sjis_str.length()=%u\n", sjis_str.length());

    //  demo 2
    std::string nameUtf8 = U8("太郎");
    int age = 15;
    format(std::cout, u8"ハロー、私の名前は %s。 年は %d だ!\n", nameUtf8.c_str(), age);
    format(std::cout, u8"漢字=한자\n");

    // demo 3
    unicode_ostream uout(cout);
    CMyClass mc;
    mc.CountUp();
    mc.CountUp();
    uout << mc << endl;
    double pi = 4 * atan(1.0);
    uout << u8"π(1)=" << pi << endl;
    uout << u8"π(2)=" << format("%.2f", pi) << endl;
    uout << 1 << u8" char*漢字=한자 " << std::string(U8(" string漢字=한자 ")) << 1.2345 << endl;
    double A = 100;
    double B = 2001.5251;
    // 書式指定(A) hex の代わりに setbase(16) を使うこともできます
    uout << hex << left << showbase << nouppercase;
    // 実際の印字処理(A)
    uout << (long long)A << endl;
    // 書式指定(B) setbase(10) の代わりに dec を使うこともできます
    uout << setbase(10) << right << setw(15)
         << setfill('_') << showpos
         << fixed << setprecision(2);
    // 実際の印字処理(B)
    uout << B << endl;

    // demo4 (v1系との互換性)
    //#define formatA format
    formatA(std::cout, u8"ハロー、私の名前は %s。 年は %d だ!\n", nameUtf8.c_str(), age);
    //#define GetConsoleOutputCP() (0)
    unicode_ostream uout2(cout, GetConsoleOutputCP());
    uout2 << "GetConsoleOutputCP()マクロを用意してダミー対応。" << endl;
    //#define GetConsoleCP() (0)
    unicode_ostream uout3(cout, GetConsoleCP());
    uout2 << "GetConsoleCP()マクロを用意してダミー対応。" << endl;

    // demo5
    uout << u"ゆーてぃーえふ16" << endl;
    uout << U"ゆーてぃーえふ32" << endl;

    std::string s = U8("abc");
    std::vector<unsigned int> v = {
        437,//OEM 米国
        737,//ギリシャ語
        775,//バルト言語
        850,//西ヨーロッパ言語
        852,//中央ヨーロッパ言語
        855,//OEM キリル
        857,//トルコ語
        858,//OEM マルチリンガル ラテン I
        860,//ポルトガル語
        861,//アイスランド語
        862,//ヘブライ語
        863,//フランス語 (カナダ)
        864,//アラビア語
        865,//北欧
        866,//キリル言語
        869,//ギリシャ語, Modern
        874,//タイ語
        932,//日本語 (シフト JIS)
        936,//簡体字中国語 (GB2312)
        949,//韓国語
        950,//繁体字中国語 (Big5)
        1250,//中央ヨーロッパ言語
        1251,//キリル言語
        1252,//西ヨーロッパ言語
        1253,//ギリシャ語
        1254,//トルコ語
        1255,//ヘブライ語
        1256,//アラビア語
        1257,//バルト言語
        1258,//ベトナム語
        1361,//韓国語 (Johab)
        65001,//Unicode (UTF-8)
    };
    int error_count = 0;
    for (std::size_t i=0; i<v.size(); i++)
    {
        std::string s2 = utf8_to_cp(s, v[i]);
        if(s2 == "abc") continue;
        uout << "ERROR: " << v[i] << ":" << utf8_to_cp(s, v[i]) << std::endl;
        error_count++;
    }
    format(std::cout, u8"変換エラー: %d個\n", error_count);

    return 0;
}
strconvxp.h
/* strconvxp.h v2.0.8              */
/* Last Modified: 2022/05/20 02:17 */
#ifndef STRCONVXP_H
#define STRCONVXP_H

#if defined(_WIN32)
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdarg.h>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include <codecvt>
#include <locale>

#if !defined(_WIN32) || defined(STRCONV_USE_ICONV)
#include <iconv.h>
template <typename X, typename Y>
static inline std::basic_string<X> iconv_translit(
    std::string to_code,
    std::string from_code,
    const std::basic_string<Y> &from_str)
{
#if defined(_WIN32)
    to_code += "//IGNORE";
#else
    to_code += "//TRANSLIT";
#endif
    void *from_begin = (void *)from_str.data();
    void *from_end = (void *)(from_str.data() + from_str.size());
    size_t buff_len = ((char *)from_end) - ((char *)from_begin);
    iconv_t icd = iconv_open(to_code.c_str(), from_code.c_str());
    if (icd == ((iconv_t) -1))
    {
        std::basic_string<X> empty;
        return empty;
    }
    while (true)
    {
        std::vector<char> buff(buff_len + 1);
        char *src_top = (char *)from_begin;
        size_t src_len = ((char *)from_end) - ((char *)from_begin);
        char *dest_top = &buff[0];
        size_t dest_len = buff_len;
        size_t ret = iconv(icd, &src_top, &src_len, &dest_top, &dest_len);
        if (ret == ((size_t) -1))
        {
            if (errno == E2BIG)
            {
                buff_len *= 2;
                continue;
            }
            else
            {
                //std::cerr << errno << std::endl;
                //iconv_close(icd);
                //std::basic_string<X> empty;
                //return empty;
            }
        }
        iconv_close(icd);
        buff.resize(buff_len - dest_len);
        std::basic_string<X> result((X *)buff.data(), (X *)(buff.data() + buff.size()));
        return result;
    }
}
#endif // !defined(_WIN32) || defined(STRCONV_USE_ICONV)

#if defined(_WIN32) && !defined(STRCONV_USE_ICONV)
static inline std::wstring cp_to_wide(const std::string &s, unsigned int codepage)
{
    int in_length = (int)s.length();
    int out_length = MultiByteToWideChar(codepage, 0, s.c_str(), in_length, 0, 0);
    std::wstring result(out_length, L'\0');
    if (out_length)
        MultiByteToWideChar(codepage, 0, s.c_str(), in_length, &result[0], out_length);
    return result;
}
static inline std::string wide_to_cp(const std::wstring &s, unsigned int codepage)
{
    int in_length = (int)s.length();
    int out_length = WideCharToMultiByte(codepage, 0, s.c_str(), in_length, 0, 0, 0, 0);
    std::string result(out_length, '\0');
    if (out_length)
        WideCharToMultiByte(codepage, 0, s.c_str(), in_length, &result[0], out_length, 0, 0);
    return result;
}
#else // !defined(_WIN32)
static inline std::wstring cp_to_wide(const std::string &s, unsigned int codepage)
{
    switch(codepage)
    {
    case 65001:
        return iconv_translit<wchar_t>("WCHAR_T", "UTF-8", s);
    default:
        std::string from_code = "CP" + std::to_string(codepage);
        return iconv_translit<wchar_t>("WCHAR_T", from_code, s);
    }
}
static inline std::string wide_to_cp(const std::wstring &s, unsigned int codepage)
{
    switch(codepage)
    {
    case 65001:
        return iconv_translit<char>("UTF-8", "WCHAR_T", s);
    default:
        std::string to_code = "CP" + std::to_string(codepage);
        return iconv_translit<char>(to_code, "WCHAR_T", s);
    }
}
#endif // _WIN32

static inline std::string cp_to_utf8(const std::string &s, unsigned int codepage)
{
    if (codepage == 65001)
        return s;
    std::wstring wide = cp_to_wide(s, codepage);
    return wide_to_cp(wide, 65001);
}
static inline std::string utf8_to_cp(const std::string &s, unsigned int codepage)
{
    if (codepage == 65001)
        return s;
    std::wstring wide = cp_to_wide(s, 65001);
    return wide_to_cp(wide, codepage);
}

static inline std::wstring ansi_to_wide(const std::string &s)
{
#if defined(_WIN32)
    return cp_to_wide(s, CP_ACP);
#else
    return cp_to_wide(s, 65001);
#endif
}
static inline std::string wide_to_ansi(const std::wstring &s)
{
#if defined(_WIN32)
    return wide_to_cp(s, CP_ACP);
#else
    return wide_to_cp(s, 65001);
#endif
}

static inline std::wstring sjis_to_wide(const std::string &s)
{
    return cp_to_wide(s, 932);
}
static inline std::string wide_to_sjis(const std::wstring &s)
{
    return wide_to_cp(s, 932);
}

static inline std::string ansi_to_utf8(const std::string &s)
{
#if defined(_WIN32)
    return cp_to_utf8(s, CP_ACP);
#else
    //return cp_to_utf8(s, 65001);
    return s;
#endif
}
static inline std::string utf8_to_ansi(const std::string &s)
{
#if defined(_WIN32)
    return utf8_to_cp(s, CP_ACP);
#else
    //return utf8_to_cp(s, 65001);
    return s;
#endif
}

static inline std::string sjis_to_utf8(const std::string &s)
{
    return cp_to_utf8(s, 932);
}
static inline std::string utf8_to_sjis(const std::string &s)
{
    return utf8_to_cp(s, 932);
}

static inline std::wstring utf8_to_wide(const std::string &s)
{
    return cp_to_wide(s, 65001);
}
static inline std::string wide_to_utf8(const std::wstring &s)
{
    return wide_to_cp(s, 65001);
}

#ifdef __cpp_char8_t
static inline std::u8string utf8_to_char8(const std::string &s)
{
    return std::u8string(s.begin(), s.end());
}
static inline std::string char8_to_utf8(const std::u8string &s)
{
    return std::string(s.begin(), s.end());
}

static inline std::wstring char8_to_wide(const std::u8string &s)
{
    return cp_to_wide(char8_to_utf8(s), 65001);
}
static inline std::u8string wide_to_char8(const std::wstring &s)
{
    return utf8_to_char8(wide_to_cp(s, 65001));
}

static inline std::u8string cp_to_char8(const std::string &s, unsigned int codepage)
{
    return utf8_to_char8(cp_to_utf8(s, codepage));
}
static inline std::string char8_to_cp(const std::u8string &s, unsigned int codepage)
{
    return utf8_to_cp(char8_to_utf8(s), codepage);
}

static inline std::u8string ansi_to_char8(const std::string &s)
{
#if defined(_WIN32)
    return cp_to_char8(s, CP_ACP);
#else
    //return cp_to_char8(s, 65001);
    return utf8_to_char8(s);
#endif
}
static inline std::string char8_to_ansi(const std::u8string &s)
{
#if defined(_WIN32)
    return char8_to_cp(s, CP_ACP);
#else
    //return char8_to_cp(s, 65001);
    return char8_to_utf8(s);
#endif
}

static inline std::u8string sjis_to_char8(const std::string &s)
{
    return cp_to_char8(s, 932);
}
static inline std::string char8_to_sjis(const std::u8string &s)
{
    return char8_to_cp(s, 932);
}
#endif

static inline std::string char16_to_utf8(const std::u16string &s)
{
    std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> convert;
    return convert.to_bytes(s);
}

static inline std::u16string utf8_to_char16(const std::string &s)
{
    std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> convert;
    return convert.from_bytes(s);
}

static inline std::string char16_to_cp(const std::u16string &s, unsigned int codepage)
{
    return utf8_to_cp(char16_to_utf8(s), codepage);
}

static inline std::string char32_to_utf8(const std::u32string &s)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
    return convert.to_bytes(s);
}

static inline std::u32string utf8_to_char32(const std::string &s)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
    return convert.from_bytes(s);
}

static inline std::string char32_to_cp(const std::u32string &s, unsigned int codepage)
{
    return utf8_to_cp(char32_to_utf8(s), codepage);
}

#ifdef __cpp_char8_t
static inline std::u8string char16_to_char8(const std::u16string &s)
{
    std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> convert;
    return utf8_to_char8(convert.to_bytes(s));
}

static inline std::u16string char8_to_char16(const std::u8string &s)
{
    std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> convert;
    return convert.from_bytes(char8_to_utf8(s));
}

static inline std::u8string char32_to_char8(const std::u32string &s)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
    return utf8_to_char8(convert.to_bytes(s));
}

static inline std::u32string char8_to_char32(const std::u8string &s)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
    return convert.from_bytes(char8_to_utf8(s));
}
#endif

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif

static inline std::string vformat(const char *format, va_list args)
{
    va_list args_copy;
    va_copy(args_copy, args);
    int len = vsnprintf(0, 0, format, args);
    if (len < 0)
    {
        va_end(args_copy);
        return "";
    }
    std::vector<char> buffer(len + 1);
    len = vsnprintf(&buffer[0], len + 1, format, args_copy);
    va_end(args_copy);
    if (len < 0)
    {
        return "";
    }
    buffer[len] = '\0';
    return &buffer[0];
}
#ifdef __cpp_char8_t
static inline std::u8string vformat(const char8_t *format, va_list args)
{
    va_list args_copy;
    va_copy(args_copy, args);
    int len = vsnprintf(0, 0, (const char *)format, args);
    if (len < 0)
    {
        va_end(args_copy);
        return u8"";
    }
    std::vector<char> buffer(len + 1);
    len = vsnprintf(&buffer[0], len + 1, (const char *)format, args_copy);
    va_end(args_copy);
    if (len < 0)
    {
        return u8"";
    }
    buffer[len] = '\0';
    return (char8_t *)&buffer[0];
}
#endif

#if defined(_MSC_VER)
#pragma warning(pop)
#endif

static inline std::string format(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    return s;
}
#ifdef __cpp_char8_t
static inline std::u8string format(const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    return s;
}
#endif

#if defined(_WIN32)
static inline HANDLE handle_for_ostream(std::ostream &ostrm)
{
    if (&ostrm == &std::cout)
    {
        return GetStdHandle(STD_OUTPUT_HANDLE);
    }
    else if (&ostrm == &std::cerr)
    {
        return GetStdHandle(STD_ERROR_HANDLE);
    }
    return INVALID_HANDLE_VALUE;
}
template <typename X>
static inline void output_to_ostream(std::ostream &ostrm, const std::basic_string<X> &s, unsigned int target_cp)
{
    static_assert(sizeof(X)==1);
    HANDLE h = handle_for_ostream(ostrm);
    if (h == INVALID_HANDLE_VALUE)
    {
        ostrm << utf8_to_cp((const char *)s.c_str(), target_cp==((unsigned int) -1) ? 65001 : target_cp) << std::flush;
    }
    DWORD dwNumberOfCharsWrite;
    if (GetFileType(h) != FILE_TYPE_CHAR)
    {
        std::string s2 = utf8_to_cp((const char *)s.c_str(), target_cp==((unsigned int) -1) ? GetConsoleOutputCP() : target_cp);
        WriteFile(h, s2.c_str(), (DWORD)s2.size(), &dwNumberOfCharsWrite, NULL);
    }
    else
    {
        std::wstring ws = utf8_to_wide((const char *)s.c_str());
        WriteConsoleW(h,
                      ws.c_str(),
                      (DWORD)ws.size(),
                      &dwNumberOfCharsWrite,
                      NULL);
    }
}
static inline void format(std::ostream &ostrm, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    output_to_ostream(ostrm, s, ((unsigned int) -1));
}
#ifdef __cpp_char8_t
static inline void format(std::ostream &ostrm, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    output_to_ostream(ostrm, s, ((unsigned int) -1));
}
#endif
#else // !defined(_WIN32)
static inline void format(std::ostream &ostrm, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    ostrm << s << std::flush;
}
#ifdef __cpp_char8_t
static inline void format(std::ostream &ostrm, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    ostrm << char8_to_utf8(s) << std::flush;
}
#endif
#endif // _WIN32

static inline std::string formatA(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
#if defined(_WIN32)
    return utf8_to_ansi(s);
#else
    return s;
#endif
}
#ifdef __cpp_char8_t
static inline std::string formatA(const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
#if defined(_WIN32)
    return char8_to_ansi(s);
#else
    return char8_to_utf8(s);
#endif
}
#endif

#if defined(_WIN32)
static inline void formatA(std::ostream &ostrm, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    output_to_ostream(ostrm, s, CP_ACP);
}
#ifdef __cpp_char8_t
static inline void formatA(std::ostream &ostrm, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    output_to_ostream(ostrm, s, CP_ACP);
}
#endif
#else // !defined(_WIN32)
static inline void formatA(std::ostream &ostrm, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    ostrm << s << std::flush;
}
#ifdef __cpp_char8_t
static inline void formatA(std::ostream &ostrm, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    ostrm << char8_to_utf8(s) << std::flush;
}
#endif
#endif // _WIN32

static inline std::string formatUtf8(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    return s;
}
#ifdef __cpp_char8_t
static inline std::string formatUtf8(const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    return char8_to_utf8(s);
}
#endif

#if defined(_WIN32)
static inline void formatUtf8(std::ostream &ostrm, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    output_to_ostream(ostrm, s, 65001);
}
#ifdef __cpp_char8_t
static inline void formatUtf8(std::ostream &ostrm, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    output_to_ostream(ostrm, s, 65001);
}
#endif
#else // !defined(_WIN32)
static inline void formatUtf8(std::ostream &ostrm, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    ostrm << s << std::flush;
}
#ifdef __cpp_char8_t
static inline void formatUtf8(std::ostream &ostrm, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    ostrm << char8_to_utf8(s) << std::flush;
}
#endif
#endif // _WIN32

class unicode_ostream
{
private:
    std::ostream *m_ostrm;
#if defined(_WIN32)
    unsigned int m_target_cp;
    bool is_ascii(const std::string &s)
    {
        for (std::size_t i = 0; i < s.size(); i++)
        {
            unsigned char c = (unsigned char)s[i];
            if (c > 0x7f)
                return false;
        }
        return true;
    }
#endif
public:
    unicode_ostream(std::ostream &ostrm, unsigned int dummy = 0) : m_ostrm(&ostrm)
    {
        (void)dummy;
#if defined(_WIN32)
        m_target_cp = GetConsoleOutputCP();
#endif
    }
    template <typename T>
    unicode_ostream &operator<<(const T &x)
    {
#if defined(_WIN32)
        std::ostringstream oss;
        oss << x;
        std::string output = oss.str();
        if (is_ascii(output))
        {
            (*m_ostrm) << x;
        }
        else
        {
            (*m_ostrm) << utf8_to_cp(output, m_target_cp);
        }
#else
        (*m_ostrm) << x;
#endif
        return *this;
    }
    unicode_ostream &operator<<(const std::string &x)
    {
#if defined(_WIN32)
        (*m_ostrm) << utf8_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << x;
#endif
        return *this;
    }
    unicode_ostream &operator<<(const char *x)
    {
#if defined(_WIN32)
        (*m_ostrm) << utf8_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << x;
#endif
        return *this;
    }
#ifdef __cpp_char8_t
    unicode_ostream &operator<<(const std::u8string &x)
    {
#if defined(_WIN32)
        (*m_ostrm) << char8_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << char8_to_utf8(x);
#endif
        return *this;
    }
    unicode_ostream &operator<<(const char8_t *x)
    {
#if defined(_WIN32)
        (*m_ostrm) << char8_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << char8_to_utf8(x);
#endif
        return *this;
    }
#endif
    unicode_ostream &operator<<(const std::u16string &x)
    {
#if defined(_WIN32)
        (*m_ostrm) << char16_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << char16_to_utf8(x);
#endif
        return *this;
    }
    unicode_ostream &operator<<(const char16_t *x)
    {
#if defined(_WIN32)
        (*m_ostrm) << char16_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << char16_to_utf8(x);
#endif
        return *this;
    }
    unicode_ostream &operator<<(const std::u32string &x)
    {
#if defined(_WIN32)
        (*m_ostrm) << char32_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << char32_to_utf8(x);
#endif
        return *this;
    }
    unicode_ostream &operator<<(const char32_t *x)
    {
#if defined(_WIN32)
        (*m_ostrm) << char32_to_cp(x, m_target_cp);
#else
        (*m_ostrm) << char32_to_utf8(x);
#endif
        return *this;
    }
    unicode_ostream &operator<<(std::ostream &(*pf)(std::ostream &)) // For manipulators...
    {
        (*m_ostrm) << pf;
        return *this;
    }
    unicode_ostream &operator<<(std::basic_ios<char> &(*pf)(std::basic_ios<char> &)) // For manipulators...
    {
        (*m_ostrm) << pf;
        return *this;
    }
};

#if !defined(_WIN32)
#define GetConsoleCP() (0)
#define GetConsoleOutputCP() (0)
#endif

#define U8(X) ((const char *)u8##X)
#define WIDE(X) (L##X)

#endif /* STRCONVXP_H */
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?