为什么我不能让一个外部类型看起来像c++中的内部类型?

问题描述 投票:0回答:1

我想维护一个大量使用内部枚举的现有API,但我需要将枚举分离出来,成为它自己的类型。

这是目前的API。

class Outer {
public:
    enum Inner {
        FIELD1
    };
};

换句话说,用户目前希望设置 Inner通过使用 Outer::Inner.如果可能的话,我想在制作新的外部类型时保留这个名字。

enum Inner {
    FIELD1
};

class Outer {
public:
    typedef Inner Inner;
}

然而,它给我一个编译器错误。

./Playground/file0.cpp:23:19: error: declaration of 'typedef enum Inner Outer::Inner' changes meaning of 'Inner' [-fpermissive]
   23 |     typedef Inner Inner;
      |                   ^~~~~
./Playground/file0.cpp:17:6: note: 'Inner' declared here as 'enum Inner'
   17 | enum Inner {
      |      ^~~~~

如果我只是改变了枚举的名字,一切都很好。

#include <cassert>

enum Enum {
    FIELD1
};

class Outer {
public:
    typedef Enum Inner;
};

int main() {

    Enum field = Enum::FIELD1;
    Outer::Inner field_alt = Outer::Inner::FIELD1;
    assert(field == field_alt);
    return 0;
}
c++ typedef inner-classes
1个回答
3
投票

由于[basic.scope.class]3的规则,这是不允许的。

一个名字 N 课堂上 S 应指同一声明的上下文,并在已完成的范围内重新评价时,应指同一声明。S. 违反本规则无需诊断。

当你 typedef Inner Inner;,你违反了这个规定。第一次 Inner 该行出现的是 使用 的名称,并发现其指的是声明的 ::Inner. 但是一旦类完全定义好了。Inner 现在指的是 typedef 声明。所以程序是不正规的NDR(GCC很好的给你一个诊断)。

你需要把它改成。

typedef ::Inner Inner;

现在,非限定名 Inner 不再使用,而是使用限定名为 ::Inner,并且在类型定义后其含义保持不变,所以应该没有问题。


6
投票

您的 typedef 对于 Inner 需要指的是 Inner 枚举 外围所以它应该是这样的。

typedef ::Inner Inner;

我一般喜欢 using 语句,不过,它看起来像这样。

using Inner = ::Inner;

这里有一个 演示


0
投票

提供的解决方案回答了我最初的问题,但遗憾的是没有解决我的麻烦。我当时并没有意识到,API其实是利用了内部枚举。

enum Inner {
    FIELD1,
    FIELD2
};

class Base {
public:
    virtual void use(Inner val) = 0;
};

class Outer : public Base {
public:
    virtual void use(Inner val) override;
};

/*
 * Some API that can't change
 */
void someAPI(Outer &inst) {
    inst.use(Outer::FIELD1);
}

换句话说,我所需要维护的API并不是 Outer::Inner::FIELD1 不过 Outer::FIELD1.

正如 @Brian 所指出的那样,使用 typedef 将 Inner enum "提升 "到 Outer 中,在当前的 c++ 中是行不通的。

最后,我发现我可以把Inner放到Base中,这样API就可以保持了。

class Base {
public:
    enum Inner {
        FIELD1,
        FIELD2
    };

    virtual void use(Inner val) = 0;
};

class Outer : public Base {
public:
    virtual void use(Inner val) override;
};

/*
 * Some API that can't change
 */
void someAPI(Outer &inst) {
    inst.use(Outer::FIELD1);
}
© www.soinside.com 2019 - 2024. All rights reserved.