可变匿名结构体

3

我想定义一个带有多个 mutable 字段的聚合体(以便将其保存在 std::setstd::priority_queue 中并在将来进行修改,同时确保保存容器不变量)。我尝试了下面的语法并且它成功编译:

#include <cstdlib>

int
main()
{
    struct X
    {
        mutable struct 
        {
            int i;
            int j;            
        };
    };
    X const x{};
    //x.i = 1;
    return EXIT_SUCCESS;
}

这里是clang 3.8的实时示例。

但是语句x.i = 1;会出错:

错误:无法将具有const限定类型“const X”的变量“x”赋值。

我的意图是将许多连续的字段分组,并对该组应用mutable关键字。

这种语法是否有误?如果是,编译器制造商允许这样的语法的目的是什么?

补充说明:

代码:

#include <cstdlib>

int
main()
{
    struct X
    {
        mutable struct 
        {
            int i;
            int j;            
        };
        void f() const { i = 1; }
    };
    X const x{};
    //x.i = 1;
    x.f();
    return EXIT_SUCCESS;
}

也会产生错误:

错误:无法在常量成员函数“f”中分配非静态数据成员

注意:成员函数“main()::X::f”在此处声明为const void f() const { i = 1; }


mutable 关键字仅在成员函数内对成员变量有意义。 - StoryTeller - Unslander Monica
1
X没有名为i的数据成员。您确定这个示例能够复现您的实际使用情况吗? - juanchopanza
@juanchopanza 我确信。我真的(相信我!)想要将一些字段分组,并同时应用“mutable”类型说明符。 - Tomilov Anatoliy
1
好的,你不能这样做,因为“X”没有名为“i”的成员。 - juanchopanza
@juanchopanza,我认为他使用了未命名结构(根据C11允许)但不适用于C++。我猜测这种非标准使用与C++标准的“mutable”混合使用将不能按预期工作。 - Christophe
@Christophe,第一个想法是正确的方向,谢谢。 - Tomilov Anatoliy
1个回答

5
问题出在C++中匿名结构体的非标准用法和mutable混合使用上。后者是一个存储类修饰符,应该用于成员而不是类型。
备选方案1:为匿名结构体定义一个中间成员:
您可以定义一个成员,根据标准C++的规则,该成员将是可变的。
struct X
{
    mutable struct 
    {
        int i;
        int j;            
    } y;
};
X const x{};
x.y.i = 1;

演示

方案二:将匿名结构中的每个成员都定义为可变的:

你也可以将匿名结构中的成员定义为可变的。由于匿名结构会将这些成员合并到封闭结构中,因此可变属性也会被传递:

struct X
{
    struct 
    {
        mutable int i;
        mutable int j;            
    };
};

在线演示

标准是什么?

C++标准不允许匿名结构体。匿名结构体是为了与C11兼容而进行的编译器扩展

C++标准虽然允许匿名联合体,但是也有限制:

9.5/6:在类作用域中,声明匿名联合体时不允许使用存储类。

因此,在编译以下代码时:

  struct X
    {
        mutable union 
        {
            int i;
            int j;            
        };
    }; 

编译器将会发出非常具体的错误提示:
prog.cpp:11:13: error: a storage class on an anonymous aggregate in class  scope is not allowed
         mutable union 

我认为,在匿名结构体上允许使用存储类说明符(并显然忽略它),而在匿名联合上发出错误提示是不一致的。据我所知,这应该报告为编译器错误。无论如何,您应该采用替代方案1(便携式和符合规范)或替代方案2(依赖于编译器,但更符合标准)。


2
@定向 你的使用方式完全不正确。这就是编译器试图告诉你的。 - juanchopanza
@juanchopanza 我完全同意。但如果这是不正确的,为什么编译器允许我定义mutable匿名结构体? - Tomilov Anatoliy
@Orient,就是这样。mutable应用于的变量在声明中缺失。 - chris
@chris 我认为这是一个关于术语严格定义和我们对它们的理解的问题。只需要查看标准文件中的措辞即可。 - Tomilov Anatoliy
我认为有另一个选择,即为每个需要的数据成员指定“可变”类型说明符,但避免冗余的匿名结构体。 - Tomilov Anatoliy
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接