不允许嵌套函数,但为什么允许嵌套函数原型?[C++]

Nav*_*K N 7 c++ compiler-construction nested function

我正在阅读相关问题,这个问题引导我提出这个问题.

请考虑以下代码

int main()
{
    string SomeString();
}
Run Code Online (Sandbox Code Playgroud)

总而言之,编译器将其作为函数原型而不是字符串对象.现在考虑以下代码.

int main()
{
    string Some()
    {
        return "";
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器说这是无效的,因为我猜不允许嵌套函数定义.如果不允许,为什么允许嵌套函数原型?它没有给予任何优势而不是混淆(或者我在这里错过了一些有效点?).

我想出以下是有效的.

int main()
{ 
  string SomeFun();
  SomeFun();
  return 0;
}

string SomeFun()
{
  std::cout << "WOW this is unexpected" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这也令人困惑.我期待函数SomeFun()只在main中有一个范围.但是我错了.为什么编译器允许编译如上所述的代码?有没有像上面这样的代码有意义的实时情况?

有什么想法吗?

ker*_*vin 8

你的原型只是' 前瞻声明 '.请查看维基百科文章.

基本上,它告诉编译器"如果以这种方式使用标签'SomeFun',不要惊慌". 但是你的链接器负责找到正确的函数体.

你实际上可以声明一个虚假的原型,例如'char SomeFun()'并在你的主要使用它.只有当链接器尝试查找伪造函数的主体时,才会出现错误.但是你的编译器很酷.

有很多好处.您必须记住函数体并不总是在同一个源代码文件中.它可以在一个链接的库中.此外,该链接库可能具有特定的"链接签名".使用条件定义甚至可以使用您的范围原型在构建时选择正确的链接签名.虽然大多数人会使用函数指针相反.

希望这可以帮助.


小智 7

正如旁注,C++ 03确实有一种定义局部函数的迂回方式.它需要滥用本地级功能:

int main()
{
    struct Local
    {
        static string Some()
        {
            return "";
        }
    };
    std::cout << Local::Some() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

  • 令人敬畏的语言滥用. (2认同)

Dre*_*ann 5

这是C的约定 - 就像很多 - C++已经采用了这种约定.

在C中的另一个函数内声明函数的能力是大多数程序员可能认为令人遗憾和不必要的决定.特别是现代的OOP设计,其功能定义比C中的要小.

如果您希望函数仅存在于另一个函数的范围内,则两个选项是boost :: lambdaC++ 1x lambda.


Joh*_*itb 5

至于为什么要申报

void f() {
    void g(); g();
}
Run Code Online (Sandbox Code Playgroud)

比这更好

void g();
void f() {
    g();
}
Run Code Online (Sandbox Code Playgroud)

如果您将声明尽可能保持在本地,这通常很好,因此尽可能少地命名冲突结果.我说在本地声明一个函数(这种方式)是否真的很幸运是有争议的,因为我认为普通包括它的标题然后采用"通常"方式更好,这对于不知道这一点的人来说也不那么混乱.有时,处理阴影函数也很有用

void f() {
    int g; 
    // oops, ::g is shadowed. But we can work around that
    {
        void g(); g();
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,在C++中我们可以g使用函数来调用函数its_namespace::g()- 但是在C的旧时代,这是不可能的,并且那个东西允许程序员仍然访问函数.还要注意,虽然在语法上它不相同,但从语义上讲,以下内容也会在本地范围内声明一个实际上针对不同范围的函数.

int main() {
    using std::exit;
    exit();
}
Run Code Online (Sandbox Code Playgroud)

作为旁注,有更多情况,例如声明的目标范围不是声明出现的范围.通常,您声明的实体成为声明出现的范围的成员.但情况并非总是如此.考虑例如朋友声明,在那里发生的事情

struct X { friend void f() { std::cout << "WoW"; } };
int main() { void f(); f(); } // works!
Run Code Online (Sandbox Code Playgroud)

即使函数声明(和定义!)f发生在范围内X,实体(函数本身)也成为封闭命名空间的成员.