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

GCC16.1中C++26反射实现JSON序列化遇constexpr错误求助

解决GCC 16.1 C++26反射实现转JSON的编译错误

问题根源分析

  1. template for编译失败:std::meta::nonstatic_data_members_of在GCC 16.1的实验性实现中,内部依赖了动态内存分配(operator new),而你的ToJson是constexpr函数——编译期常量表达式不允许动态内存操作,因此触发错误。
  2. expand workaround异常:原expand函数用std::vector收集元信息,再通过std::meta::substitute替换模板参数时,GCC的反射实现不支持这种动态容器的参数替换逻辑,导致can_substitute returned false异常。

修正方案

方案1:移除constexpr限定(最简单有效)

生成JSON字符串无需在编译期完成,直接去掉ToJson的constexpr修饰,让函数在运行期执行,即可避开编译期内存分配限制:

#include <meta>
#include <string>
#include <iostream>

template <typename ValueT> auto ToJson(const ValueT& Value)
{
    if constexpr (not std::is_class_v<ValueT>)
    {
        return std::to_string(Value);
    }
    else
    {
        std::string OutputResult = "{\n";

        template for (constexpr std::meta::info Member : std::meta::nonstatic_data_members_of(^^ValueT, std::meta::access_context::current()))
        {
            OutputResult += '"'
            + std::string(std::meta::identifier_of(Member))
            + "\" : "
            + ToJson(Value.[:Member:])
            + ",\n";
        }

        // 修复JSON末尾逗号问题,避免生成无效格式
        if (!OutputResult.empty() && OutputResult.back() == '\n') {
            OutputResult.pop_back();
            if (OutputResult.back() == ',') {
                OutputResult.pop_back();
            }
            OutputResult += '\n';
        }

        return OutputResult + "}";
    }
}

struct EpicClass
{
public:
    int MyInt = 4;
    struct
    {
        int OtherInt = 5;
        char Guy = 0;
    } Other;
};

int main()
{
    EpicClass g_Epic = EpicClass();
    std::cout << ToJson(g_Epic) << "\n";
}

编译命令保持不变:

/opt/gcc-16.1/bin/g++ -std=c++26 main.cpp -o app -freflection

方案2:修复expand实现(保留编译期能力)

若需保留ToJson的constexpr特性,需修改expand函数,用编译期可构造的std::array替代std::vector,同时明确模板参数类型:

#include <meta>
#include <string>
#include <iostream>
#include <array>

namespace __impl {
    template<std::meta::info... Members>
    struct replicator_type {
        template<typename F>
        constexpr void operator>>(F body) const {
            (body.template operator()<Members>(), ...);
        }
    };
}

template<typename R>
consteval auto expand(R range) {
    constexpr auto member_count = std::meta::range_size(range);
    std::array<std::meta::info, member_count> member_infos{};
    std::size_t idx = 0;
    for (auto r : range) {
        member_infos[idx++] = ^^r;
    }
    return std::meta::substitute(^^__impl::replicator_type, member_infos);
}

template <typename ValueT> constexpr auto ToJson(const ValueT& Value)
{
    if constexpr (not std::is_class_v<ValueT>)
    {
        return std::to_string(Value);
    }
    else
    {
        std::string OutputResult = "{\n";

        [: expand(std::meta::nonstatic_data_members_of(^^ValueT, std::meta::access_context::current())) :] >> [&]<std::meta::info Member>
        {
            OutputResult += '"'
            + std::string(std::meta::identifier_of(Member))
            + "\" : "
            + ToJson(Value.[:Member:])
            + ",\n";
        };

        // 修复JSON末尾逗号问题
        if (!OutputResult.empty() && OutputResult.back() == '\n') {
            OutputResult.pop_back();
            if (OutputResult.back() == ',') {
                OutputResult.pop_back();
            }
            OutputResult += '\n';
        }

        return OutputResult + "}";
    }
}

struct EpicClass
{
public:
    int MyInt = 4;
    struct
    {
        int OtherInt = 5;
        char Guy = 0;
    } Other;
};

int main()
{
    EpicClass g_Epic = EpicClass();
    std::cout << ToJson(g_Epic) << "\n";
}

关键修改点:

  • 将replicator_type的模板参数明确为std::meta::info...,消除类型歧义
  • 用std::array替代std::vector,避免动态内存分配,满足编译期常量要求
  • lambda模板参数指定为std::meta::info Member,匹配替换后的参数类型

额外注意事项

  • GCC 16.1的C++26反射特性仍处于实验阶段,部分实现细节可能与标准草案存在差异,可参考GCC官方的反射实现说明调整代码
  • 当前代码仅遍历类的直接成员,若需递归处理嵌套结构体(如EpicClass::Other的内部成员),需在ToJson中增加对成员类型的判断,递归调用自身
  • 生成JSON时的末尾逗号问题必须处理,否则输出的JSON格式无效

内容的提问来源于stack exchange,提问作者Man In. Jail

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 04:37:26