我想维护一个大量使用内部枚举的现有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;
}
由于[basic.scope.class]3的规则,这是不允许的。
一个名字
N
课堂上S
应指同一声明的上下文,并在已完成的范围内重新评价时,应指同一声明。S
. 违反本规则无需诊断。
当你 typedef Inner Inner;
,你违反了这个规定。第一次 Inner
该行出现的是 使用 的名称,并发现其指的是声明的 ::Inner
. 但是一旦类完全定义好了。Inner
现在指的是 typedef 声明。所以程序是不正规的NDR(GCC很好的给你一个诊断)。
你需要把它改成。
typedef ::Inner Inner;
现在,非限定名 Inner
不再使用,而是使用限定名为 ::Inner
,并且在类型定义后其含义保持不变,所以应该没有问题。
您的 typedef
对于 Inner
需要指的是 Inner
枚举 外围所以它应该是这样的。
typedef ::Inner Inner;
我一般喜欢 using
语句,不过,它看起来像这样。
using Inner = ::Inner;
这里有一个 演示
提供的解决方案回答了我最初的问题,但遗憾的是没有解决我的麻烦。我当时并没有意识到,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);
}