C ++:在另一个函数中声明函数的用法是什么?

时间:2015-01-07 15:17:18

标签: c++ function design-patterns

Stanley Lippman" C ++入门"在第234页提到

  

通常,在本地声明一个函数是个坏主意。然而,   为了解释范围如何与重载相互作用,我们将违反此规定   练习并使用本地函数声明。

...
void print(const string &);
void print(double); // overloads the print function
void fooBar(int ival)
{ ...
  // bad practice: usually it's a bad idea to declare functions at local scope
  void print(int); // new scope: hides previous instances of print
  print(ival); // ok: print(int) is visible
  print(3.14); // ok: calls print(int); print(double) is hidden
}

然而,这样做可能有意义,在函数体内声明一个函数?

我记得Scheme中的类似代码:

(define (PowerSet set)
   (if (null? set) '(())
      (let ((PowerSetAfterHead (PowerSet (cdr set) ) ))
         (append PowerSetAfterHead
            (PowerSet (cdr set) )
            (map
               (lambda (subset)
                  (cons (car set) subset
                  )
               )
               (PowerSet (cdr set) )                                 
            )
         )
      )
   )
)

它通常用于避免滥用"本地功能"打算只用于外部功能?像内部类的东西?或者它在某些设计模式中是否有用?

2 个答案:

答案 0 :(得分:2)

当调用函数时存在歧义时会出现问题。因此,为了避免某些范围内的歧义,您可以重新声明所需的函数,该函数隐藏具有外部范围相同名称的所有其他函数。

考虑以下简单示例。如果您运行以下程序

#include <iostream>

void f( int ) { std::cout << "f( int )" << std::endl; }
void f( double ) { std::cout << "f( double )" << std::endl; }

int main() 
{
    f( 10l );

    return 0;
}

你会收到类似

的错误

prog.cpp:10:9:错误:调用重载&#39; f(long int)&#39;是模棱两可的f(10l);

但是如果你要在main中添加一个函数f的声明,就像这样

#include <iostream>

void f( int ) { std::cout << "f( int )" << std::endl; }
void f( double ) { std::cout << "f( double )" << std::endl; }

int main() 
{
    void f( double );
    f( 10l );

    return 0;
}

代码将被编译,输出看起来像

f( double )

答案 1 :(得分:2)

您的方案示例都声明并定义了本地函数。

C ++示例只是在本地声明一个函数。

这些是不同的东西。

您可以在C ++ 11中使用lambdas创建方案局部函数的粗略等价物。

在本地声明一个函数只是说&#34;存在这个名称和签名的功能&#34;。更重要的是,它在比函数外部更窄的范围内这样做,并且由于在所述较窄范围内存在函数,因此只考虑它们的重载(而不是更广泛范围内的函数)。

没有创建新功能 - 必须在别处定义。 (你不能在C ++中定义一个局部函数,除了像本地类方法和lambdas这样的东西)

您可以使用它来更改重载解析的工作方式,但这不是一个好主意。如果您有过载歧义,最好手动转换类型然后调用重载集,并使其正常解析。

另一种方法是仅声明要调用的重载,然后调用它。这可能导致令人惊讶的行为,所以如果可以的话,只能在非常狭窄的范围内这样做,并记录你为什么这样做以及可能发生的问题(因为很少有程序员会在他们的前面有范围隐藏的重载规则)在阅读代码时没有至少一点提示的大脑。)

我认为我从未遇到过必须在本地申报函数的情况。

有几次我这样做是因为我正在攻击一些严重的泥码代码,并希望在原型/调试目的上做出极其局部的改变。我只是声明了一个函数签名并在某个地方调用它。该函数是在其他地方的同一个库中的另一个.cpp文件中的静态本地,我删除了那里的静态并测试了调用它的结果。

这保存了创建头文件(或修改一个),正式公开它,包括我们在哪里使用它。在投入生产之前,我会经历这样的步骤(并且可能在我使用它时清理静态本地函数的界面)。

所以,我用它来做一个快速而又脏的原型黑客。我最后一次这样做了,在我做了原型黑客之后我最终还原了它,这更容易,因为我只在1点触摸了2个文件。