以下代码从 GCC 4.7.1 编译到但不包括 GCC 11.1没有问题:
constexpr int SomeValue = 0;
void test () {
void (SomeValue) ();
}
在 GCC 11.x 上它失败了:
<source>:4:23: error: 'void SomeValue()' redeclared as different kind of entity
4 | void (SomeValue) ();
| ^
<source>:1:15: note: previous declaration 'constexpr const int SomeValue'
1 | constexpr int SomeValue = 0;
| ^~~~~~~~~
但是“重新声明为不同类型的实体”的错误对我来说似乎很奇怪:除了不明确的解析可能性,范围是不同的。此外,这些测试都在自 4.7.1 (包括 11.x) 以来的所有 GCC 版本上编译,即使 AFAIK 每个都重新声明SomeValue
为“不同类型的实体”:
constexpr int SomeValue = 0;
void test1 () { typedef void (SomeValue) (); }
void test2 () { double SomeValue; }
void test3 () { using SomeValue = char *; }
void test4 () { void (* SomeValue) (); }
void test5 () { struct SomeValue { }; }
void test6 () { enum class SomeValue { }; }
作为一个相对不那么荒谬的示例,此代码从 11.x 开始也以类似的方式失败:
constexpr int SomeValue = 0;
struct SomeClass {
explicit SomeClass (int) { }
void operator () () { }
};
void test () {
SomeClass(SomeValue)();
}
尽管在这种情况下,它前面有一个在 11.x 之前也不存在的 vexing-parse 警告(警告在这里但不在上面的事实是有道理的,警告在 11 之前没有出现的事实.x 是有趣的一点):
<source>: In function 'void test()':
<source>:9:25: warning: empty parentheses were disambiguated as a function declaration [-Wvexing-parse]
9 | SomeClass(SomeValue)();
| ^~
<source>: At global scope:
<source>:9:26: error: 'SomeClass SomeValue()' redeclared as different kind of entity
9 | SomeClass(SomeValue)();
| ^
<source>:1:15: note: previous declaration 'constexpr const int SomeValue'
1 | constexpr int SomeValue = 0;
| ^~~~~~~~~
Compiler returned: 1
可是等等!还有更多!
这段代码——由于与上面相同的解析歧义,我预计在 11.x 上会失败——在所有这些版本的 GCC(包括 11.x)上编译得很好:
constexpr int SomeValue = 0;
auto closure = [] (int) {
return [] () { };
};
void test () {
closure(SomeValue)(); // <-- doesn't cause any problems
}
没有警告或任何东西。
所以...这里发生了什么事?为什么在这些特定情况下“重新声明为不同类型的实体”只是一个问题SomeValue
,并且仅从 GCC 11.1 开始,为什么不会closure(SomeValue)()
遇到与SomeClass(SomeValue)()
?
还有什么变化?GCC在这里正确吗?它是 GCC 11.x 中引入的新错误吗?或者也许是最终在 11.x 中修复的旧错误?或者根本不是一个错误,而其他的东西发生了变化?
我正在努力想出一个一致的解释。