Why did C++ never allow functions to be used before they're declared? [closed]

感情迁移 提交于 2019-12-03 05:28:30

Template parsing

Consider the following line of code:

a < b , c > d;

How would you parse this? There are actually two ways, depending on what a, b, c and d are. Firstly, a variable declaration

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

in the case that a is a known template type, b and c are other known types. Secondly,

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

in the case that a, b, c and d are all variables of some sort.

The vexing parse

Or here another one:

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

This could be a function declaration (a function with return type a and argument type c) or a variable definition (whose type is a and whose constructor argument is c).

Conclusion

There's a lot of stuff like that, unfortunately. I'm not sure, if it would be impossible to write a compiler that can deal with that kind of stuff, but it would at least be very hard to write one. Compilation times are a serious issue in C++ already. This would only make it worse. Also: It is good practice to only use what you have defined or declared already, even in other languages.

Constraints of the committee

Even if it would be reasonably possible to implement this feature, it would kill backwards compatibility. Function overloading resolution only takes prior declarations into account and the interpretation of function calls may change depending on the place a function call is written. That's the way C++ is put together. Now, the C++ standards committee is big on back-wards compatibility. In particular: They do not want to break any existing code (and rightly so). Your proposal would surely break existing code which is a no-go for the language designers.

MSalters

The current answer is because it would be unparseable.

Consider two-phase name lookup for templates, and in particular the need for typename. In templates, type-dependent names may not have been declared yet. To be able to parse them, we absolutely need typename. Without that, parsing would grind to a halt and we can't reliably proceed, so we couldn't even provide the type needed to fix the parsing problem. It's a chicken and egg problem: If we need to have parsed line 10 to parse line 5, line 10 will never be parsed because we break at line 5. typename helps us get past line 5 so we can learn the actual type on line 10.

Here, we'd have a similar problem. Consider this code under your assumptions:

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

To parse this code, we need to know whether Foo denotes a type or function.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!