为什么C ++在它们被声明之前从不允许使用函数?

时间:2014-07-24 05:34:15

标签: c++ c++11 compiler-construction declaration

好的,我知道这看起来像是Why do functions need to be declared before they are used?的副本,但现有的答案似乎并没有完全解决所有细节。

我知道C ++最初是在80年代设计的,所以它可以在一次通过中翻译,因为计算机很慢。好。但是最新的标准是在2011年发布的,所以我不明白为什么C ++编译器现在不能做需要多次传递的事情。它仍然会伤害性能,是的,但只有在它真的变得必要的时候。所以以下仍然只需要一次通过:

void foo();
int main() { foo(); }
void foo() {}

而对于以下内容,编译器可以生成两个(并且更慢),因为它不知道foo是函数还是类型,直到它看到下面的声明:

int main() { foo(); }
void foo() {}

如果你试图使用一个函数而不首先声明它,并且声明根本不在当前的翻译单元中, 那么 则会出错。但是如果它在同一个翻译单元中,那么编译器就可以进行额外的传递。

我的同事辩称,这样的功能可以节省大量的开发人员时间,并且可以避免声明和定义不匹配的问题。而且我确信这已被多次提出并且每次都被拒绝。拒绝它的实际推理是什么,即。,委员会的理由是什么?

2 个答案:

答案 0 :(得分:4)

模板解析

考虑以下代码行:

a < b , c > d;

你会如何解析这个?实际上有两种方式,具体取决于abcd。首先,变量声明

a<b,c>   d;
^^^^^^   ^
 Type   Var

如果a是已知模板类型,bc是其他已知类型。其次,

   a<b   ,   c<d ;
   ^^^       ^^^ 
boolean expressions

如果abcd都是某种变量。

令人烦恼的解析

或者另一个:

a b(c); // is 'b' a function or a variable?

这可以是函数声明(返回类型为a且参数类型为c的函数)或变量定义(其类型为a且其构造函数参数为{{1 }})。

结论

不幸的是,有很多类似的东西。我不确定,如果编写一个可以处理这种东西的编译器是不可能的,但至少要编写一个很难。编译时间已经是C ++中的一个严重问题。这只会让情况变得更糟。另外:优秀的做法是仅使用您已定义或已声明的内容,即使在其他语言中也是如此。

委员会的限制

即使可以合理地实施此功能,也会导致向后兼容性。函数重载解析只考虑先前的声明,函数调用的解释可能会根据函数调用的位置而改变。这就是C ++的组合方式。现在,C ++标准委员会在后向兼容性方面做得很好。特别是:他们不想破坏任何现有代码(这是正确的)。你的提议肯定会破坏现有的代码,这对于语言设计者来说是不可取的。

答案 1 :(得分:1)

目前的答案是因为它无法解析。

考虑模板的两阶段名称查找,特别是the need for typename。在模板中,可能尚未声明类型相关的名称。为了能够解析它们,我们绝对需要typename。如果没有这个,解析就会停止,我们无法可靠地继续进行,因此我们甚至无法提供修复解析问题所需的类型。这是鸡和蛋的问题:如果我们需要解析第10行来解析第5行,那么第10行永远不会被解析,因为我们在第5行中断。typename帮助我们越过第5行,所以我们可以在第10行学习实际类型。

在这里,我们遇到了类似的问题。在您的假设下考虑此代码:

struct Foo { };
int bar () { return Foo(); }
int Foo () { return 42; }

要解析此代码,我们需要知道Foo是否表示类型或函数。