我们可以在 C++ 中的函数内部使用函数吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4324763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can we have functions inside functions in C++?
提问by Rella
I mean something like:
我的意思是这样的:
int main()
{
void a()
{
// code
}
a();
return 0;
}
回答by sbi
Modern C++ - Yes with lambdas!
现代 C++ - 是的 lambdas!
In current versions of c++ (C++11, C++14, and C++17), you can have functions inside functions in the form of a lambda:
在当前版本的 c++(C++11、C++14 和 C++17)中,您可以在函数内部以 lambda 的形式拥有函数:
int main() {
// This declares a lambda, which can be called just like a function
auto print_message = [](std::string message)
{
std::cout << message << "\n";
};
// Prints "Hello!" 10 times
for(int i = 0; i < 10; i++) {
print_message("Hello!");
}
}
Lambdas can also modify local variables through **capture-by-reference*. With capture-by-reference, the lambda has access to all local variables declared in the lambda's scope. It can modify and change them normally.
Lambda 还可以通过 **capture-by-reference* 修改局部变量。通过引用捕获,lambda 可以访问在 lambda 范围内声明的所有局部变量。它可以正常修改和更改它们。
int main() {
int i = 0;
// Captures i by reference; increments it by one
auto addOne = [&] () {
i++;
};
while(i < 10) {
addOne(); //Add 1 to i
std::cout << i << "\n";
}
}
C++98 and C++03 - Not directly, but yes with static functions inside local classes
C++98 和 C++03 - 不是直接的,而是在本地类中使用静态函数
C++ doesn't support that directly.
C++ 不直接支持。
That said, you can have local classes, and they can have functions (non-static
or static
), so you can get this to some extend, albeit it's a bit of a kludge:
也就是说,您可以拥有本地类,并且它们可以拥有函数(非static
或static
),因此您可以将其扩展到一定程度,尽管它有点杂乱:
int main() // it's int, dammit!
{
struct X { // struct's as good as class
static void a()
{
}
};
X::a();
return 0;
}
However, I'd question the praxis. Everyone knows (well, now that you do, anyway :)
) C++ doesn't support local functions, so they are used to not having them. They are not used, however, to that kludge. I would spend quite a while on this code to make sure it's really only there to allow local functions. Not good.
但是,我会质疑实践。每个人都知道(好吧,现在你知道了,无论如何:)
)C++ 不支持本地函数,所以他们习惯了没有它们。然而,他们并不习惯于那种混乱。我会在这段代码上花很长时间来确保它真的只允许本地函数。不好。
回答by Konrad Rudolph
For all intents and purposes, C++ supports this via lambdas:1
出于所有意图和目的,C++ 通过lambdas支持这一点:1
int main() {
auto f = []() { return 42; };
std::cout << "f() = " << f() << std::endl;
}
Here, f
is a lambda object that acts as a local function in main
. Captures can be specified to allow the function to access local objects.
这里,f
是一个 lambda 对象,它在main
. 可以指定捕获以允许函数访问本地对象。
Behind the scenes, f
is a function object(i.e. an object of a type that provides an operator()
). The function object type is created by the compiler based on the lambda.
在幕后,f
是一个函数对象(即提供一个类型的对象operator()
)。函数对象类型由编译器基于 lambda 创建。
1since C++11
1自 C++11
回答by Sebastian Mach
Local classes have already been mentioned, but here is a way to let them appear even more as local functions, using an operator() overload and an anonymous class:
已经提到了本地类,但这里有一种方法可以让它们更多地作为本地函数出现,使用 operator() 重载和匿名类:
int main() {
struct {
unsigned int operator() (unsigned int val) const {
return val<=1 ? 1 : val*(*this)(val-1);
}
} fac;
std::cout << fac(5) << '\n';
}
I don't advise on using this, it's just a funny trick (can do, but imho shouldn't).
我不建议使用它,这只是一个有趣的技巧(可以做,但恕我直言不应该)。
2014 Update:
2014年更新:
With the rise of C++11 a while back, you can now have local functions whose syntax is a little reminiscient of JavaScript:
随着 C++11 的兴起,你现在可以拥有语法有点像 JavaScript 的本地函数:
auto fac = [] (unsigned int val) {
return val*42;
};
回答by Nim
No.
不。
What are you trying to do?
你想做什么?
workaround:
解决方法:
int main(void)
{
struct foo
{
void operator()() { int a = 1; }
};
foo b;
b(); // call the operator()
}
回答by Leo Davidson
Old answer: You can, sort-of, but you have to cheat and use a dummy class:
旧答案:您可以,有点,但您必须作弊并使用虚拟课程:
void moo()
{
class dummy
{
public:
static void a() { printf("I'm in a!\n"); }
};
dummy::a();
dummy::a();
}
Newer answer: Newer versions of C++ also support lambdas to do this better/properly. See answers higher up the page.
较新的答案:较新版本的 C++ 也支持 lambdas 以更好/正确地执行此操作。请参阅页面上方的答案。
回答by luis.espinal
As others have mentioned, you can use nested functions by using the gnu language extensions in gcc. If you (or your project) sticks to the gcc toolchain, your code will be mostly portable across the different architectures targeted by the gcc compiler.
正如其他人提到的,您可以通过使用 gcc 中的 gnu 语言扩展来使用嵌套函数。如果您(或您的项目)坚持使用 gcc 工具链,您的代码将主要可移植到 gcc 编译器所针对的不同架构中。
However, if there is a possible requirement that you might need to compile code with a different toolchain, then I'd stay away from such extensions.
但是,如果您可能需要使用不同的工具链编译代码,那么我会远离此类扩展。
I'd also tread with care when using nested functions. They are a beautiful solution for managing the structure of complex, yet cohesive blocks of code (the pieces of which are not meant for external/general use.) They are also very helpful in controlling namespace pollution (a very real concern with naturally complex/long classes in verbose languages.)
在使用嵌套函数时,我也会小心谨慎。它们是管理复杂但有凝聚力的代码块结构的漂亮解决方案(其中的部分不供外部/一般使用。)它们在控制命名空间污染方面也非常有帮助(对于自然复杂的/冗长语言的长类。)
But like anything, they can be open to abuse.
但就像任何事情一样,他们可能会受到虐待。
It is sad that C/C++ does not support such features as an standard. Most pascal variants and Ada do (almost all Algol-based languages do). Same with JavaScript. Same with modern languages like Scala. Same with venerable languages like Erlang, Lisp or Python.
遗憾的是,C/C++ 不支持这样的特性作为标准。大多数 pascal 变体和 Ada 都可以(几乎所有基于 Algol 的语言都可以)。与 JavaScript 相同。与 Scala 等现代语言相同。与 Erlang、Lisp 或 Python 等古老语言相同。
And just as with C/C++, unfortunately, Java (with which I earn most of my living) does not.
就像 C/C++ 一样,不幸的是,Java(我靠它谋生)没有。
I mention Java here because I see several posters suggesting usage of classes and class' methods as alternatives to nested functions. And that's also the typical workaround in Java.
我在这里提到 Java 是因为我看到一些海报建议使用类和类的方法作为嵌套函数的替代方法。这也是 Java 中的典型解决方法。
Short answer: No.
简短的回答:没有。
Doing so tend to introduce artificial, needless complexity on a class hierarchy. With all things being equal, the ideal is to have a class hierarchy (and its encompassing namespaces and scopes) representing an actual domain as simple as possible.
这样做往往会在类层次结构中引入人为的、不必要的复杂性。在所有条件相同的情况下,理想的情况是拥有一个类层次结构(及其包含的命名空间和作用域),以尽可能简单地表示实际域。
Nested functions help deal with "private", within-function complexity. Lacking those facilities, one should try to avoid propagating that "private" complexity out and into one's class model.
嵌套函数有助于处理“私有”的函数内复杂性。缺乏这些设施,应该尽量避免将“私有”复杂性传播到类模型中。
In software (and in any engineering discipline), modeling is a matter of trade-offs. Thus, in real life, there will be justified exceptions to those rules (or rather guidelines). Proceed with care, though.
在软件(以及任何工程学科)中,建模是一个权衡问题。因此,在现实生活中,这些规则(或更确切地说是指导方针)会有合理的例外。不过,请谨慎行事。
回答by Donald Duck
You can't have local functions in C++. However, C++11 has lambdas. Lambdas are basically variables that work like functions.
C++ 中不能有局部函数。但是,C++11 有lambdas。Lambda 基本上是像函数一样工作的变量。
A lambda has the type std::function
(actually that's not quite true, but in most cases you can suppose it is). To use this type, you need to #include <functional>
. std::function
is a template, taking as template argument the return type and the argument types, with the syntax std::function<ReturnType(ArgumentTypes)
. For example, std::function<int(std::string, float)>
is a lambda returning an int
and taking two arguments, one std::string
and one float
. The most common one is std::function<void()>
, which returns nothing and takes no arguments.
lambda 具有类型std::function
(实际上这并不完全正确,但在大多数情况下您可以假设它是)。要使用这种类型,您需要#include <functional>
. std::function
是一个模板,将返回类型和参数类型作为模板参数,语法为std::function<ReturnType(ArgumentTypes)
. 例如,std::function<int(std::string, float)>
是一个 lambda 返回 anint
并接受两个参数, onestd::string
和 one float
。最常见的是std::function<void()>
,它不返回任何内容并且不接受任何参数。
Once a lambda is declared, it is called just like a normal function, using the syntax lambda(arguments)
.
一旦声明了一个 lambda,它就会像普通函数一样被调用,使用语法lambda(arguments)
.
To define a lambda, use the syntax [captures](arguments){code}
(there are other ways of doing it, but I won't mention them here). arguments
is what arguments the lambda takes, and code
is the code that should be run when the lambda is called. Usually you put [=]
or [&]
as captures. [=]
means that you capture all variables in the scope in which the value is defined by value, which means that they will keep the value that they had when the lambda was declared. [&]
means that you capture all variables in the scope by reference, which means that they will always have their current value, but if they are erased from memory the program will crash. Here are some examples:
要定义 lambda,请使用语法[captures](arguments){code}
(还有其他方法可以做到,但我不会在这里提及它们)。arguments
是 lambda 所采用的参数,并且code
是调用 lambda 时应该运行的代码。通常你把[=]
或[&]
作为捕获。[=]
意味着您捕获值由值定义的范围内的所有变量,这意味着它们将保留声明 lambda 时拥有的值。[&]
意味着您通过引用捕获作用域中的所有变量,这意味着它们将始终具有当前值,但如果从内存中擦除它们,程序将崩溃。这里有些例子:
#include <functional>
#include <iostream>
int main(){
int x = 1;
std::function<void()> lambda1 = [=](){
std::cout << x << std::endl;
};
std::function<void()> lambda2 = [&](){
std::cout << x << std::endl;
};
x = 2;
lambda1(); //Prints 1 since that was the value of x when it was captured and x was captured by value with [=]
lambda2(); //Prints 2 since that's the current value of x and x was captured by value with [&]
std::function<void()> lambda3 = [](){}, lambda4 = [](){}; //I prefer to initialize these since calling an uninitialized lambda is undefined behavior.
//[](){} is the empty lambda.
{
int y = 3; //y will be deleted from the memory at the end of this scope
lambda3 = [=](){
std::cout << y << endl;
};
lambda4 = [&](){
std::cout << y << endl;
};
}
lambda3(); //Prints 3, since that's the value y had when it was captured
lambda4(); //Causes the program to crash, since y was captured by reference and y doesn't exist anymore.
//This is a bit like if you had a pointer to y which now points nowhere because y has been deleted from the memory.
//This is why you should be careful when capturing by reference.
return 0;
}
You can also capture specific variables by specifying their names. Just specifying their name will capture them by value, specifying their name with a &
before will capture them by reference. For example, [=, &foo]
will capture all variables by value except foo
which will be captured by reference, and [&, foo]
will capture all variables by reference except foo
which will be captured by value. You can also capture only specific variables, for example [&foo]
will capture foo
by reference and will capture no other variables. You can also capture no variables at all by using []
. If you try to use a variable in a lambda that you didn't capture, it won't compile. Here is an example:
您还可以通过指定名称来捕获特定变量。仅指定它们的名称将通过值捕获它们,使用&
before指定它们的名称将通过引用捕获它们。例如,[=, &foo]
将按值捕获所有变量,除了foo
将通过引用[&, foo]
捕获的变量foo
,将按引用捕获所有变量,但将通过值捕获的变量除外。您还可以仅捕获特定变量,例如[&foo]
将foo
通过引用捕获而不捕获其他变量。您还可以使用[]
. 如果您尝试在未捕获的 lambda 中使用变量,它将无法编译。下面是一个例子:
#include <functional>
int main(){
int x = 4, y = 5;
std::function<void(int)> myLambda = [y](int z){
int xSquare = x * x; //Compiler error because x wasn't captured
int ySquare = y * y; //OK because y was captured
int zSquare = z * z; //OK because z is an argument of the lambda
};
return 0;
}
You can't change the value of a variable that was captured by value inside a lambda (variables captured by value have a const
type inside the lambda). To do so, you need to capture the variable by reference. Here is an exampmle:
您不能更改由 lambda 内的值捕获的变量的值(由值捕获的变量const
在 lambda 内具有类型)。为此,您需要通过引用捕获变量。这是一个例子:
#include <functional>
int main(){
int x = 3, y = 5;
std::function<void()> myLambda = [x, &y](){
x = 2; //Compiler error because x is captured by value and so it's of type const int inside the lambda
y = 2; //OK because y is captured by reference
};
x = 2; //This is of course OK because we're not inside the lambda
return 0;
}
Also, calling uninitialized lambdas is undefined behavior and will usually cause the program to crash. For example, never do this:
此外,调用未初始化的 lambdas 是未定义的行为,通常会导致程序崩溃。例如,永远不要这样做:
std::function<void()> lambda;
lambda(); //Undefined behavior because lambda is uninitialized
Examples
例子
Here is the code for what you wanted to do in your question using lambdas:
以下是您想在问题中使用 lambda 执行的操作的代码:
#include <functional> //Don't forget this, otherwise you won't be able to use the std::function type
int main(){
std::function<void()> a = [](){
// code
}
a();
return 0;
}
Here is a more advanced example of a lambda:
这是一个更高级的 lambda 示例:
#include <functional> //For std::function
#include <iostream> //For std::cout
int main(){
int x = 4;
std::function<float(int)> divideByX = [x](int y){
return (float)y / (float)x; //x is a captured variable, y is an argument
}
std::cout << divideByX(3) << std::endl; //Prints 0.75
return 0;
}
回答by royas
All this tricks just look (more or less) as local functions, but they don't work like that. In a local function you can use local variables of it's super functions. It's kind of semi-globals. Non of these tricks can do that. The closest is the lambda trick from c++0x, but it's closure is bound in definition time, not the use time.
所有这些技巧看起来(或多或少)都像是本地函数,但它们并不是那样工作的。在局部函数中,您可以使用其超级函数的局部变量。这是一种半全球性的。这些技巧都不能做到这一点。最接近的是来自 c++0x 的 lambda 技巧,但它的闭包是在定义时间而不是使用时间中绑定的。
回答by Thomas Owens
No, it's not allowed. Neither C nor C++ support this feature by default, however TonyK points out (in the comments) that there are extensions to the GNU C compiler that enable this behavior in C.
不,这是不允许的。默认情况下,C 和 C++ 都不支持此功能,但是 TonyK 指出(在评论中)有 GNU C 编译器的扩展可以在 C 中启用此行为。
回答by Prasoon Saurav
You cannot define a free function inside another in C++.
你不能在 C++ 中定义另一个内部的自由函数。