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

问题描述 投票:0回答:2

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) )                                 
            )
         )
      )
   )
)

它通常用于隐藏仅用于外部函数使用的“本地函数”的误用吗?类似内部类的东西?或者说它在某些设计模式中有用吗?

c++ function design-patterns scope
2个回答
4
投票

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

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

#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: 错误:重载的“f(long int)”调用不明确 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 )

3
投票

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

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

这些是不同的事情。

您可以在 C++11 中使用 lambda 创建方案局部函数的大致等效项。

在本地声明一个函数只是说“存在一个具有该名称和签名的函数”。更重要的是,它在比函数外部更窄的范围内执行此操作,并且由于在所述较窄范围内有函数,因此仅考虑它们重载(而不是在更广泛范围内的函数)。

没有创建新函数——它必须在其他地方定义。 (你不能在 C++ 中定义本地函数,除非本地类方法和 lambda 之类的东西)

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

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

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

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

这节省了创建头文件(或修改头文件)的时间,正式公开它,包括我们使用它的所述头文件。在投入生产之前,我会执行类似的步骤(并且可能会清理该静态本地函数的接口)。

所以,我用它来进行快速而肮脏的原型破解。上次我这样做时,我在完成原型破解后最终恢复了它,这更容易,因为我只在 1 个位置触及了 2 个文件。

© www.soinside.com 2019 - 2024. All rights reserved.