Allman 好きのための .clang-format

clang-format で Allman にしたい場合の .clang-format を提示します。
Googleスタイルをベースに3か所変更してます。
添付した「.clang-format(Allman適用済み)」をホームディレクトリにおいてください。
Allman ではどういう風に整形されるのか分からない方は、文末に整形例を添付しましたのでそちらをご覧ください。

※ IndentWidth を 4 にしてありますが、これを 2 に変える場合は、AccessModifierOffset も -4 から -2 に変えてください。

.clang-format のカスタマイズについては：

https://qiita.com/koyukitukimino/items/9b8f74d1ae307a7017d3

もご覧ください。

```
AccessModifierOffset とは：
IndentWidth が 4だと・・・

class Calc
{
    public: // ← これもインデントされてしまう。
    static int add(int a, int b);
}；

これを AccessModifierOffset で補正します。IndentWidth をマイナスにした数値にしておけば・・・

class Calc
{
public: // ← インデント(+4 -4 = 0) でインデントされない。
    static int add(int a, int b);
}；

となり、わりと一般的な整形結果となります。

```

```text:Googleスタイルからの差分を調べる
clang-format --style=Google --dump-config > .clang-format.original
diff .clang-format.original .clang-format
```

```text:上記実行結果(Googleスタイルからの差分)
-AccessModifierOffset: -1
+AccessModifierOffset: -4
-BreakBeforeBraces: Attach
+BreakBeforeBraces: Allman
-IndentWidth:     2
+IndentWidth:     4
```

```text:.clang-format(Allman適用済み)
---
Language:        Cpp
# BasedOnStyle:  Google
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
  Enabled:         false
  AcrossEmptyLines: false
  AcrossComments:  false
  AlignCompound:   false
  PadOperators:    true
AlignConsecutiveBitFields:
  Enabled:         false
  AcrossEmptyLines: false
  AcrossComments:  false
  AlignCompound:   false
  PadOperators:    false
AlignConsecutiveDeclarations:
  Enabled:         false
  AcrossEmptyLines: false
  AcrossComments:  false
  AlignCompound:   false
  PadOperators:    false
AlignConsecutiveMacros:
  Enabled:         false
  AcrossEmptyLines: false
  AcrossComments:  false
  AlignCompound:   false
  PadOperators:    false
AlignEscapedNewlines: Left
AlignOperands:   Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
  - __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
  AfterCaseLabel:  false
  AfterClass:      false
  AfterControlStatement: Never
  AfterEnum:       false
  AfterFunction:   false
  AfterNamespace:  false
  AfterObjCDeclaration: false
  AfterStruct:     false
  AfterUnion:      false
  AfterExternBlock: false
  BeforeCatch:     false
  BeforeElse:      false
  BeforeLambdaBody: false
  BeforeWhile:     false
  IndentBraces:    false
  SplitEmptyFunction: true
  SplitEmptyRecord: true
  SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit:     80
CommentPragmas:  '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat:   false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: NextLine
BasedOnStyle:    ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
  - foreach
  - Q_FOREACH
  - BOOST_FOREACH
IfMacros:
  - KJ_IF_MAYBE
IncludeBlocks:   Regroup
IncludeCategories:
  - Regex:           '^<ext/.*\.h>'
    Priority:        2
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '^<.*\.h>'
    Priority:        1
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '^<.*'
    Priority:        2
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '.*'
    Priority:        3
    SortPriority:    0
    CaseSensitive:   false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequiresClause: true
IndentWidth:     4
IndentWrappedFunctionNames: false
InsertBraces:    false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd:   ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
PPIndentWidth:   -1
RawStringFormats:
  - Language:        Cpp
    Delimiters:
      - cc
      - CC
      - cpp
      - Cpp
      - CPP
      - 'c++'
      - 'C++'
    CanonicalDelimiter: ''
    BasedOnStyle:    google
  - Language:        TextProto
    Delimiters:
      - pb
      - PB
      - proto
      - PROTO
    EnclosingFunctions:
      - EqualsProto
      - EquivToProto
      - PARSE_PARTIAL_TEXT_PROTO
      - PARSE_TEST_PROTO
      - PARSE_TEXT_PROTO
      - ParseTextOrDie
      - ParseTextProtoOrDie
      - ParseTestProto
      - ParsePartialTestProto
    CanonicalDelimiter: pb
    BasedOnStyle:    google
ReferenceAlignment: Pointer
ReflowComments:  true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes:    CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
  AfterControlStatements: true
  AfterForeachMacros: true
  AfterFunctionDefinitionName: false
  AfterFunctionDeclarationName: false
  AfterIfMacros:   true
  AfterOverloadedOperator: false
  AfterRequiresInClause: false
  AfterRequiresInExpression: false
  BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles:  Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
  Minimum:         1
  Maximum:         -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard:        Auto
StatementAttributeLikeMacros:
  - Q_EMIT
StatementMacros:
  - Q_UNUSED
  - QT_REQUIRE_VERSION
TabWidth:        8
UseCRLF:         false
UseTab:          Never
WhitespaceSensitiveMacros:
  - STRINGIZE
  - PP_STRINGIZE
  - BOOST_PP_STRINGIZE
  - NS_SWIFT_NAME
  - CF_SWIFT_NAME
...


```

```cpp:Allmanで整形したソース
/* strconv-again.h v1.0.0          */
/* Last Modified: 2023/04/08 02:53 */
#ifndef STRCONV_AGAIN_H
#define STRCONV_AGAIN_H

#include <stdarg.h>
#include <windows.h>

#include <codecvt>
#include <iostream>
#include <locale>
#include <sstream>
#include <string>
#include <vector>

static inline std::wstring cp_to_wide(const std::string &s, UINT 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, UINT 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;
}

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

static inline std::wstring ansi_to_wide(const std::string &s)
{
    return cp_to_wide(s, CP_ACP);
}
static inline std::string wide_to_ansi(const std::wstring &s)
{
    return wide_to_cp(s, CP_ACP);
}

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::wstring utf8_to_wide(const std::string &s)
{
    return cp_to_wide(s, CP_UTF8);
}
static inline std::string wide_to_utf8(const std::wstring &s)
{
    return wide_to_cp(s, CP_UTF8);
}

static inline std::string ansi_to_utf8(const std::string &s)
{
    return cp_to_utf8(s, CP_ACP);
}
static inline std::string utf8_to_ansi(const std::string &s)
{
    return utf8_to_cp(s, CP_ACP);
}

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);
}

#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), CP_UTF8);
}
static inline std::u8string wide_to_char8(const std::wstring &s)
{
    return utf8_to_char8(wide_to_cp(s, CP_UTF8));
}

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

static inline std::u8string ansi_to_char8(const std::string &s)
{
    return cp_to_char8(s, CP_ACP);
}
static inline std::string char8_to_ansi(const std::u8string &s)
{
    return char8_to_cp(s, CP_ACP);
}

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

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

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

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

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)
{
    try
    {
        std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
        return convert.to_bytes(s);
    }
    catch (...)
    {
        return "";
    }
}

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

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)
{
    try
    {
        std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> convert;
        return utf8_to_char8(convert.to_bytes(s));
    }
    catch (...)
    {
        return u8"";
    }
}

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

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

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

static inline std::wstring vformat(const wchar_t *format, va_list args)
{
    int len = _vsnwprintf(0, 0, format, args);
    if (len < 0) return L"";
    std::vector<wchar_t> buffer(len + 1);
    len = _vsnwprintf(&buffer[0], len, format, args);
    if (len < 0) return L"";
    buffer[len] = L'\0';
    return &buffer[0];
}
static inline std::string vformat(const char *format, va_list args)
{
    int len = _vsnprintf(0, 0, format, args);
    if (len < 0) return "";
    std::vector<char> buffer(len + 1);
    len = _vsnprintf(&buffer[0], len, format, args);
    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)
{
    int len = _vsnprintf(0, 0, (const char *)format, args);
    if (len < 0) return u8"";
    std::vector<char> buffer(len + 1);
    len = _vsnprintf(&buffer[0], len, (const char *)format, args);
    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::wstring format(const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::wstring s = vformat(format, args);
    va_end(args);
    return s;
}
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

static inline void format(std::ostream &ostrm, const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::wstring s = vformat(format, args);
    va_end(args);
    ostrm << wide_to_utf8(s) << std::flush;
}
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

static inline std::string formatA(const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::wstring s = vformat(format, args);
    va_end(args);
    return wide_to_ansi(s);
}
static inline std::string formatA(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    return utf8_to_ansi(s);
}
#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);
    return char8_to_ansi(s);
}
#endif

static inline void formatA(std::ostream &ostrm, const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::wstring s = vformat(format, args);
    va_end(args);
    ostrm << wide_to_ansi(s) << std::flush;
}
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 << utf8_to_ansi(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_ansi(s) << std::flush;
}
#endif

static inline void dbgmsg(const wchar_t *title, const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::wstring s = vformat(format, args);
    va_end(args);
    MessageBoxW(0, s.c_str(), title, MB_OK);
}
static inline void dbgmsg(const char *title, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    MessageBoxW(0, utf8_to_wide(s).c_str(), utf8_to_wide(title).c_str(), MB_OK);
}
#ifdef __cpp_char8_t
static inline void dbgmsg(const char8_t *title, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    MessageBoxW(0, char8_to_wide(s).c_str(), char8_to_wide(title).c_str(),
                MB_OK);
}
#endif

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;
}
static inline void dbgout(std::ostream &ostrm, const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::wstring ws = vformat(format, args);
    va_end(args);
    HANDLE h = handle_for_ostream(ostrm);
    if (h == INVALID_HANDLE_VALUE)
    {
        return;
    }
    DWORD dwNumberOfCharsWrite;
    if (GetFileType(h) != FILE_TYPE_CHAR)
    {
        std::string s = wide_to_cp(ws, GetConsoleOutputCP());
        WriteFile(h, s.c_str(), (DWORD)s.size(), &dwNumberOfCharsWrite, NULL);
    }
    else
    {
        WriteConsoleW(h, ws.c_str(), (DWORD)ws.size(), &dwNumberOfCharsWrite,
                      NULL);
    }
}
static inline void dbgout(std::ostream &ostrm, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    std::string s = vformat(format, args);
    va_end(args);
    HANDLE h = handle_for_ostream(ostrm);
    if (h == INVALID_HANDLE_VALUE)
    {
        return;
    }
    DWORD dwNumberOfCharsWrite;
    if (GetFileType(h) != FILE_TYPE_CHAR)
    {
        s = utf8_to_cp(s, GetConsoleOutputCP());
        WriteFile(h, s.c_str(), (DWORD)s.size(), &dwNumberOfCharsWrite, NULL);
    }
    else
    {
        std::wstring ws = utf8_to_wide(s);
        WriteConsoleW(h, ws.c_str(), (DWORD)ws.size(), &dwNumberOfCharsWrite,
                      NULL);
    }
}
#ifdef __cpp_char8_t
static inline void dbgout(std::ostream &ostrm, const char8_t *format, ...)
{
    va_list args;
    va_start(args, format);
    std::u8string s = vformat(format, args);
    va_end(args);
    HANDLE h = handle_for_ostream(ostrm);
    if (h == INVALID_HANDLE_VALUE)
    {
        return;
    }
    DWORD dwNumberOfCharsWrite;
    if (GetFileType(h) != FILE_TYPE_CHAR)
    {
        std::string str = char8_to_cp(s, GetConsoleOutputCP());
        WriteFile(h, (const char *)str.c_str(), (DWORD)str.size(),
                  &dwNumberOfCharsWrite, NULL);
    }
    else
    {
        std::wstring ws = char8_to_wide(s);
        WriteConsoleW(h, ws.c_str(), (DWORD)ws.size(), &dwNumberOfCharsWrite,
                      NULL);
    }
}
#endif

class unicode_ostream
{
private:
    std::ostream *m_ostrm;
    UINT 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;
    }

public:
    unicode_ostream(std::ostream &ostrm, UINT target_cp = CP_ACP)
        : m_ostrm(&ostrm), m_target_cp(target_cp)
    {
    }
    std::ostream &stream() { return *m_ostrm; }
    void stream(std::ostream &ostrm) { m_ostrm = &ostrm; }
    UINT target_cp() { return m_target_cp; }
    void target_cp(UINT cp) { m_target_cp = cp; }
    template <typename T>
    unicode_ostream &operator<<(const T &x)
    {
        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);
        }
        return *this;
    }
    unicode_ostream &operator<<(const std::wstring &x)
    {
        (*m_ostrm) << wide_to_cp(x, m_target_cp);
        return *this;
    }
    unicode_ostream &operator<<(const wchar_t *x)
    {
        (*m_ostrm) << wide_to_cp(x, m_target_cp);
        return *this;
    }
    unicode_ostream &operator<<(const std::string &x)
    {
        (*m_ostrm) << utf8_to_cp(x, m_target_cp);
        return *this;
    }
    unicode_ostream &operator<<(const char *x)
    {
        (*m_ostrm) << utf8_to_cp(x, m_target_cp);
        return *this;
    }
#ifdef __cpp_char8_t
    unicode_ostream &operator<<(const std::u8string &x)
    {
        (*m_ostrm) << char8_to_cp(x, m_target_cp);
        return *this;
    }
    unicode_ostream &operator<<(const char8_t *x)
    {
        (*m_ostrm) << char8_to_cp(x, m_target_cp);
        return *this;
    }
#endif
    unicode_ostream &operator<<(const std::u16string &x)
    {
        (*m_ostrm) << char16_to_cp(x, m_target_cp);
        return *this;
    }
    unicode_ostream &operator<<(const char16_t *x)
    {
        (*m_ostrm) << char16_to_cp(x, m_target_cp);
        return *this;
    }
    unicode_ostream &operator<<(const std::u32string &x)
    {
        (*m_ostrm) << char32_to_cp(x, m_target_cp);
        return *this;
    }
    unicode_ostream &operator<<(const char32_t *x)
    {
        (*m_ostrm) << char32_to_cp(x, m_target_cp);
        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;
    }
};

#define U8(X) ((const char *)u8##X)
#define U16(X) (u##X)
#define U32(X) (U##X)
#define WIDE(X) (L##X)

#endif /* STRCONV_AGAIN_H */
```