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

Why can't I make a external type appear like an inner type in c++?

本文关键字:类型 c++ 内部 看起来 不能 外部 为什么      更新时间:2024-05-23

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

这是当前的API:

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

换句话说,用户当前期望通过使用Outer::Inner来设置Inners。如果可能的话,当我制作新的外部类型时,我想保留这个名称:

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;
}

Innertypedef需要引用外部范围中的Inner枚举,因此它应该如下所示:

typedef ::Inner Inner;

不过,我通常更喜欢using语句,它看起来像这样:

using Inner = ::Inner;

这是的演示

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

S中使用的名称N在其上下文中以及在S的完整范围中重新评估时应引用相同的声明。违反此规则不需要进行诊断。

执行typedef Inner Inner;时,您违反了此规则。Inner第一次出现在该行时,它是名称的使用,并被发现引用声明::Inner。但是一旦类被完全定义,Inner现在引用typedef声明。因此,该程序是格式错误的NDR(GCC足够好,可以为您提供诊断(。

您需要将其更改为:

typedef ::Inner Inner;

现在,不再使用不合格名称Inner;相反,您使用的是限定名::Inner,其含义在typedef之后保持不变,因此应该没有问题。

提供的解决方案回答了我最初的问题,但不幸的是,没有解决我的问题。当时我还没有意识到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所指出的,在当前的c++中,使用typedef将内部枚举"提升"到外部是不可行的。

最终,我发现我可以将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);
}