首页 > 解决方案 > 将大括号括起来的初始化列表作为结构返回

问题描述

g++ -c test.cpp给出下面用或编译的简化代码g++ -std=c++17 -c test.cpp

#include <cstddef>

struct sd_bus_vtable {
        union {
                struct {
                        size_t element_size;
                } start;
                struct {
                        const char *member;
                        const char *signature;
                } signal;
        } x;
};

sd_bus_vtable get()
{
    return {
        .x = {
            .signal = {
                .member = "",
                .signature= "",
            }
        }
    };
}

它在 GCC 9.2.0 和 clang 5/6 上编译良好,但在 8.3.0 或 7.4.0 上编译失败,并显示以下错误消息:

test.cpp:25:5: error: could not convert ‘{{{"", ""}}}’ from ‘&lt;brace-enclosed initializer list>’ to ‘sd_bus_vtable’
     };

要解决它,get()可以按如下方式更改该功能,但它看起来不太干净......

sd_bus_vtable get()
{
    struct sd_bus_vtable t = {
        .x = {
            .signal = {
                .member = "",
                .signature= "",
            }
        }
    };
    return t;
}

问题是,上面的代码是否有效?如果是,它是否会触发 GCC 中已在 GCC9 中修复的某些错误?

标签: c++gccclang

解决方案


标准 C++ 中还没有指定的初始化器语法。它计划包含在 C++20 中,但尚未最终确定或发布。

因此,您依赖于支持此即将推出的功能的编译器作为扩展。

在已发布的 C++ 标准中,除了第一个之外,没有办法为联合成员提供这样的初始化程序。(你可以在类定义中有一个默认的成员初始化器)。

与此同时,以下代码将起作用:

sd_bus_vtable get()
{
    sd_bus_vtable r{};
    r.x.signal = {"", ""};
    return r;    
}

注意:此方法(使用赋值运算符切换联合的活动成员)仅在所有联合成员都具有平凡的构造函数和析构函数时才有效。否则,您需要手动销毁和创建 .

也可以省略名称x(这称为匿名联合),然后可以访问联合成员的名称,就好像它们是封闭结构的成员一样。


推荐阅读