You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为std::format实现std::wstring自定义格式化器(GCC编译报错)

问题:std::wstring自定义格式化器在GCC/libstd++下编译失败

我尝试为std::format实现自定义格式化器,将std::wstring转换为std::string,并把无法转换的字符替换为?。代码在Clang+libc环境下正常运行,但在GCC+libstd下编译报错。

原代码

#include <format>
#include <string>
#include <iostream>

template<>
struct std::formatter<std::wstring> : public std::formatter<std::string> {

    template<typename ParsContext>
    constexpr auto parse(ParsContext& ctx) {
        return std::begin(ctx);
    }

    template<typename FormatContext>
    auto format(const std::wstring &obj, FormatContext &ctx) const {
        std::string result{};
        for(const auto & wch : obj){
            if(wch < 0x80){
                std::format_to(std::back_inserter(result), "{}", static_cast<char>(wch));
            }else{
                std::format_to(std::back_inserter(result), "?");
            }
        }
        return std::formatter<std::string>::format(result, ctx);
    }
};

int main(){
    std::wstring test{L"Hello wide world.こんにちは、안녕하세요!"};
    std::cout << std::format("{}", test); 
}

编译错误信息

/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/format:3029:19: error: no matching function for call to 'std::basic_string_view<char>::basic_string_view(<brace-enclosed initializer list>)'
 3029 |             _M_set(_Td{__v.data(), __v.size()});
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/string_view:146:7: note: candidate: 'constexpr std::basic_string_view<_CharT, _Traits>::basic_string_view(const _CharT*, size_type) [with _CharT = char; _Traits = std::char_traits<char>; size_type = long unsigned int]'
  146 |       basic_string_view(const _CharT* __str, size_type __len) noexcept
      |       ^~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/string_view:146:39: note:   no known conversion for argument 1 from 'wchar_t*' to 'const char*'
  146 |       basic_string_view(const _CharT* __str, size_type __len) noexcept

问题原因

错误源于继承std::formatter<std::string>的实现方式。libstd++的std::formatter<std::string>内部逻辑会假设格式化对象是char类型的序列,当特化std::formatter<std::wstring>并继承它时,部分内部代码会错误地尝试用std::wstring::data()返回的wchar_t*构造char类型的std::string_view,导致类型不匹配。

解决方案

不要通过继承std::formatter<std::string>来实现,而是直接实现格式化器的完整逻辑,或者显式使用std::formatter<std::string>的实例处理转换后的结果。

方案1:保留格式说明符支持

该方案复用std::string的格式解析逻辑,支持宽度、对齐等格式说明符:

#include <format>
#include <string>
#include <iostream>

template<>
struct std::formatter<std::wstring> {
    // 复用std::string的格式解析规则
    template<typename ParsContext>
    constexpr auto parse(ParsContext& ctx) {
        return std::formatter<std::string>{}.parse(ctx);
    }

    template<typename FormatContext>
    auto format(const std::wstring& obj, FormatContext& ctx) const {
        std::string result;
        result.reserve(obj.size()); // 预分配空间提升效率
        for (wchar_t wch : obj) {
            result.push_back(wch < 0x80 ? static_cast<char>(wch) : '?');
        }
        // 使用独立的std::string格式化器处理结果
        return std::formatter<std::string>{}.format(result, ctx);
    }
};

int main(){
    std::wstring test{L"Hello wide world.こんにちは、안녕하세요!"};
    std::cout << std::format("{:40}", test); // 支持格式说明符
}

方案2:无中间字符串的高效实现

直接将转换后的字符写入格式化上下文的迭代器,避免中间字符串分配:

#include <format>
#include <string>
#include <iostream>

template<>
struct std::formatter<std::wstring> {
    // 可选:支持std::string的格式说明符
    template<typename ParsContext>
    constexpr auto parse(ParsContext& ctx) {
        return std::formatter<std::string>{}.parse(ctx);
    }

    template<typename FormatContext>
    auto format(const std::wstring& obj, FormatContext& ctx) const {
        auto out = ctx.out();
        for (wchar_t wch : obj) {
            *out++ = wch < 0x80 ? static_cast<char>(wch) : '?';
        }
        return out;
    }
};

int main(){
    std::wstring test{L"Hello wide world.こんにちは、안녕하세요!"};
    std::cout << std::format("{}", test); 
}

两种方案都能在libc和libstd环境下正常编译运行。

内容的提问来源于stack exchange,提问作者Flip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:08:15