C++:在另一个函数中声明一个函数有什么用?
C++: what's the usage of declaring a function inside another function?
斯坦利·李普曼 "C++ primer" 在第 234 页提到
Ordinarily, it is a bad idea to declare a function locally. However,
to explain how scope interacts with overloading, we will violate this
practice and use local function declarations.
...
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) )
)
)
)
)
)
它通常用于隐藏仅供外部函数使用的 "local function" 的误用吗?像内部类?或者在某些设计模式中有用吗?
当调用函数时出现歧义时就会出现问题。因此,为了避免某些范围内的歧义,您可以重新声明所需的函数,该函数隐藏所有其他与外部范围同名的函数。
考虑以下简单示例。如果你运行下面的程序
#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 )
您的方案示例既声明又定义了局部函数。
C++ 示例只是在本地声明一个函数。
这些是不同的东西。
您可以在 C++11 中使用 lambda 创建大致等效的方案局部函数。
在本地声明一个函数只是说 "there exist a function of this name and signature"。更重要的是,它在比函数外部的范围更窄的范围内这样做,并且由于在所述更窄范围内有函数,只有它们被认为是重载(而不是更广泛范围内的函数)。
没有创建新函数 -- 它必须在别处定义。 (你不能在 C++ 中定义本地函数,除非像本地 class 方法和 lambdas 之类的东西)
您可以使用它来更改重载解析的工作方式,但这很少是个好主意。如果你有重载歧义,你最好手动转换类型,然后调用重载集,让它正常解析。
另一种方法是只声明要调用的重载,然后调用它。这可能会导致令人惊讶的行为,所以如果可以的话,只在非常狭窄的范围内这样做,并记录你为什么这样做以及可能发生的问题(因为很少有程序员会在他们的前面有范围隐藏重载规则)在没有任何提示的情况下阅读代码时的大脑)。
我认为我从未 运行 遇到过必须在本地声明函数的情况。
我这样做的少数几次是因为我正在侵入一些严重的泥代码球,并想为 prototype/debugging 目的进行非常局部的更改。我只是声明了一个函数签名并在某处调用它。该函数是其他地方同一个库中另一个 .cpp 文件中的静态局部函数,我在那里删除了静态函数并测试了调用它的结果。
这节省了创建头文件(或修改头文件),正式公开它,包括我们使用它的地方所说的头文件。在投入生产之前,我会经历这样的步骤(并且可能会在我处理它时清理该静态本地函数的接口)。
因此,我将其用于快速而肮脏的原型破解。上次我这样做时,我在完成原型破解后最终恢复了它,这更容易,因为我只在 1 个位置触摸了 2 个文件。
斯坦利·李普曼 "C++ primer" 在第 234 页提到
Ordinarily, it is a bad idea to declare a function locally. However, to explain how scope interacts with overloading, we will violate this practice and use local function declarations.
...
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) )
)
)
)
)
)
它通常用于隐藏仅供外部函数使用的 "local function" 的误用吗?像内部类?或者在某些设计模式中有用吗?
当调用函数时出现歧义时就会出现问题。因此,为了避免某些范围内的歧义,您可以重新声明所需的函数,该函数隐藏所有其他与外部范围同名的函数。
考虑以下简单示例。如果你运行下面的程序
#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 )
您的方案示例既声明又定义了局部函数。
C++ 示例只是在本地声明一个函数。
这些是不同的东西。
您可以在 C++11 中使用 lambda 创建大致等效的方案局部函数。
在本地声明一个函数只是说 "there exist a function of this name and signature"。更重要的是,它在比函数外部的范围更窄的范围内这样做,并且由于在所述更窄范围内有函数,只有它们被认为是重载(而不是更广泛范围内的函数)。
没有创建新函数 -- 它必须在别处定义。 (你不能在 C++ 中定义本地函数,除非像本地 class 方法和 lambdas 之类的东西)
您可以使用它来更改重载解析的工作方式,但这很少是个好主意。如果你有重载歧义,你最好手动转换类型,然后调用重载集,让它正常解析。
另一种方法是只声明要调用的重载,然后调用它。这可能会导致令人惊讶的行为,所以如果可以的话,只在非常狭窄的范围内这样做,并记录你为什么这样做以及可能发生的问题(因为很少有程序员会在他们的前面有范围隐藏重载规则)在没有任何提示的情况下阅读代码时的大脑)。
我认为我从未 运行 遇到过必须在本地声明函数的情况。
我这样做的少数几次是因为我正在侵入一些严重的泥代码球,并想为 prototype/debugging 目的进行非常局部的更改。我只是声明了一个函数签名并在某处调用它。该函数是其他地方同一个库中另一个 .cpp 文件中的静态局部函数,我在那里删除了静态函数并测试了调用它的结果。
这节省了创建头文件(或修改头文件),正式公开它,包括我们使用它的地方所说的头文件。在投入生产之前,我会经历这样的步骤(并且可能会在我处理它时清理该静态本地函数的接口)。
因此,我将其用于快速而肮脏的原型破解。上次我这样做时,我在完成原型破解后最终恢复了它,这更容易,因为我只在 1 个位置触摸了 2 个文件。