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

嵌套花括号initializer_list在GCC、MSVC中存储失败,仅Clang支持

跨编译器兼容的std::initializer_list嵌套初始化问题

问题描述

需要临时存储std::initializer_list<topic>用于处理,允许通过嵌套花括号向register_topics函数传入结构化的topic对象。每个topic对象会将初始化列表存储至完整表达式结束,供register_topics访问并将主题存入vector等容器。这段代码在Clang 10及以上版本可正常编译,但在GCC 12和MSVC中编译失败,请问是代码问题还是编译器问题?如何修改实现跨主流编译器兼容?

代码示例

#include <cstdio>
#include <initializer_list>

struct topic
{
    using callback_type = void (*)();
    topic() = default;
    topic(const char* name, callback_type fn, std::initializer_list<topic> init = {})
        :   name_{name},
            fn_{fn},
            init_{init}
    {
        
    }

    const char* name_;
    callback_type fn_;
    std::initializer_list<topic> init_;
};

void register_topics(topic topic_structure)
{
    /* 在此处处理topic_structure,需访问topic对象临时存储的initializer_list */
}

int main()
{
    auto lambda1 = []() -> void {};

    register_topics({ "hello", lambda1, { {"hello2", lambda1}, { "hello3", lambda1 }} });
}

GCC 12编译错误

<source>: In constructor 'topic::topic(const char*, callback_type, std::initializer_list<topic>)':
<source>:11:13: error: could not convert '{init}' from '<brace-enclosed initializer list>' to 'std::initializer_list<topic>'
   11 |             init_{init}
      |             ^~~~~~~~~~~
      |             |
      |             <brace-enclosed initializer list>

原因分析

这是代码写法不符合C标准导致的兼容性问题。问题出在构造函数的成员初始化列表中:用init_{init}这种花括号初始化方式赋值std::initializer_list<topic>类型的成员。虽然Clang对这种写法做了扩展支持,但GCC和MSVC严格遵循C标准——std::initializer_list的构造不支持将另一个std::initializer_list对象放在花括号里进行隐式转换。

修改方案

将构造函数成员初始化列表中的init_{init}改为init_(init),直接使用括号初始化而非花括号初始化:

修改后的完整代码

#include <cstdio>
#include <initializer_list>

struct topic
{
    using callback_type = void (*)();
    topic() = default;
    topic(const char* name, callback_type fn, std::initializer_list<topic> init = {})
        : name_{name},
          fn_{fn},
          init_(init)  // 替换花括号为括号,符合标准初始化方式
    {
    }

    const char* name_;
    callback_type fn_;
    std::initializer_list<topic> init_;
};

void register_topics(topic topic_structure)
{
    /* 在此处处理topic_structure,需访问topic对象临时存储的initializer_list */
}

int main()
{
    auto lambda1 = []() -> void {};

    register_topics({ "hello", lambda1, { {"hello2", lambda1}, { "hello3", lambda1 }} });
}

额外说明

std::initializer_list的底层数组是临时对象,其生命周期仅持续到完整表达式结束。当前代码中register_topics按值接收topic参数,topic对象的init_指向的临时数组会在register_topics调用完成前保持有效,完全符合需求,无需额外修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:51:30