20

大多数像我这样的 C++ 程序员在某些时候都犯了以下错误:

class C { /*...*/ };

int main() {
  C c();     // declares a function c taking no arguments returning a C,
             // not, as intended by most, an object c of type C initialized
             // using the default constructor.
  c.foo();   // compiler complains here.

  //...
}

现在虽然一旦你知道错误就很明显了,但我想知道这种局部函数声明是否有任何合理的用途,除非你可以这样做——特别是因为没有办法在同一个函数中定义这样的局部函数堵塞; 你必须在别处定义它。

我认为 Java 风格的本地类是我经常使用的一个非常好的特性,尤其是匿名排序。甚至本地 C++ 类(可以具有内联定义的成员函数)也有一些用途。但是这个没有定义的局部函数声明对我来说似乎很尴尬。它只是一个 C-legacy 还是有一些我不知道的更深层次的用例?

为非信徒编辑C c():不是函数指针声明。

这个节目

int main()
{
  void g();
  cout << "Hello ";
  g();
  return 0;
}

void g()
{
  cout << "world." << endl;
}

输出Hello world.这个程序

void fun()
{
  cout << "world." << endl;
}

int main()
{
  void g();
  g = fun;
  cout << "Hello ";
  g();
  return 0;
}

不编译。gcc 抱怨:

错误:无法在赋值中将 'void ()()' 转换为 'void ()()'

喜剧:

错误:表达式必须是可修改的左值
4

7 回答 7

13

我能想到的唯一用途是缩小函数声明的范围:

int main()
{
    void doSomething();
    doSomething();
    return 0;
}

void otherFunc()
{
    doSomething();  // ERROR, doSomething() not in scope
}

void doSomething()
{
    ...
}

当然,有更好的解决方案。如果你需要隐藏一个函数,你真的应该通过将函数移动到单独的模块中来重构你的代码,以便需要调用你想要隐藏的函数的函数都在同一个模块中。然后,您可以通过将其声明为静态(C 方式)或将其放入匿名命名空间(C++ 方式)来使该功能模块本地化。

于 2009-06-23T19:42:44.637 回答
2

这是一个前向声明原型。可以想象,如果你有很多局部函数,或者局部函数相互调用与定义顺序相反,你可能需要它。

于 2009-06-23T19:28:06.337 回答
2

我能看到的唯一合理的用途是只允许编译单元中的一个函数知道另一个编译单元中定义的函数。我认为这将是一个有点合理的用途,但这是我能想到的唯一一个,而且我认为这是矫枉过正。

于 2009-06-23T20:06:15.073 回答
2

当我想将局部函数声明作为参数传递给其他函数时,我想要 C 语言中的局部函数声明。我一直在用其他语言做这件事。原因是为了封装数据结构的实现。

例如,我定义了一些数据结构,例如树或图,并且我不想公开其内部实现的细节,例如因为我可能想要更改或改变它。所以我公开了它的元素的访问器和修改器函数,以及一个遍历元素的遍历函数。遍历函数的参数是一个对元素进行操作的函数;遍历函数的任务是对每个元素执行参数函数,并可能以某种方式聚合结果。现在当我调用遍历函数时,参数函数通常是一些依赖于局部状态的特殊操作,因此应该定义为局部函数。必须将带有包含局部状态的变量的函数推送到外部是全局的,或者推送到专门为保存它们而创建的内部类中,屁股丑。但这是我在 C 和 Java 中遇到的问题,而不是在 C++ 中。

于 2009-06-24T12:26:48.033 回答
1

我有时这样做的原因与我们鼓励在第一次使用之前(而不是更早)声明变量的原因相同,即提高可读性。(是的,我意识到对于变量来说它更重要,因为它使您无需在您认为第一次使用变量之前检查变量是否被使用)。让原型(特别是如果它比仅仅涉及更多c())靠近函数调用可以提高可读性。C c()不幸的是,特殊情况会误导人类这一事实,但在本地声明函数的一般想法是有优点的。

当然,对于已经在范围内的函数名也是如此。为什么不在每次使用之前重新声明每个功能?我对此的回答是:做所有事情都要适度。太多的混乱会阻碍可读性(以及可维护性——如果函数的签名发生变化)。因此,虽然我不会对此做出规定,但有时在本地声明函数很有用。

于 2009-06-24T06:38:41.537 回答
1

就像在这个答案的第三个片段中所说的那样,它可以帮助进行范围阴影。

#include <stdio.h>

void c(); // Prototype of a function named ``c''

int main() {

    c(); // call the function

    { // additional scoppe needed for C, not for C++
        int c = 0; // shadow the c function with a c integer variable
        c++;
        {
            void c(); // hide the c integer variable back with the c function
            c();
        }
        ++c;
    } //!

    return 0;
}

void c() {
    printf("Called\n");
}

我认为这种用法可能不会经常有用,并且有可能在任何设计良好的程序中都不会出现。

我仍然认为这是该功能最可能的原因,最近为变量定义函数听起来并不正确。

于 2012-01-11T15:34:41.813 回答
-1

如果您想在声明不带参数的函数和使用默认析构函数实例化类之间有所不同,请跳过括号。

class C
{
  public:
    void foo() {}
};


int main()
{
    // declare function d, taking no arguments, returning fresh C
    C d();

    // instantiate class (leave parenthesis out)
    C c;
    c.foo();

    // call declared function
    C goo = d();

    return 0;
}

C d()
{
    C c;
    // ..
    return c;
}
于 2009-06-23T20:23:07.613 回答