我的意思是:
int main()
{
void a()
{
// code
}
a();
return 0;
}
我的意思是:
int main()
{
void a()
{
// code
}
a();
return 0;
}
Answers:
在当前版本的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!");
}
}
Lambda还可通过“按引用捕获”来修改局部变量。通过按引用捕获,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 ++不直接支持它。
就是说,您可以拥有局部类,并且它们可以具有函数(非static
或static
),因此您可以对此进行一定程度的扩展,尽管有点麻烦:
int main() // it's int, dammit!
{
struct X { // struct's as good as class
static void a()
{
}
};
X::a();
return 0;
}
但是,我会质疑实践。每个人都知道(好吧,无论如何,现在:)
),C ++不支持局部函数,因此它们习惯于不使用局部函数。但是,它们并不适用于这种冲突。我会花一些时间在这段代码上,以确保它仅在此处允许本地函数。不好。
int main()
和int main(int argc, char* argv[])
int main()
且int main(int argc, char* argv[])
必须得到支持,可能会得到其他人的支持,但它们都具有int返回值。
出于所有意图和目的,C ++通过lambdas支持此功能:1
int main() {
auto f = []() { return 42; };
std::cout << "f() = " << f() << std::endl;
}
这f
是一个lambda对象,在其中充当局部函数main
。可以指定捕获以允许函数访问本地对象。
幕后f
是一个函数对象(即提供的类型的对象operator()
)。函数对象类型由编译器基于lambda创建。
自C ++ 11起1
+1
。
已经提到了本地类,但是这是一种通过使用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';
}
我不建议您使用它,这只是一个有趣的把戏(可以,但恕我直言不应该)。
随着C ++ 11的兴起,您现在可以拥有一些局部函数,其语法有点像JavaScript:
auto fac = [] (unsigned int val) {
return val*42;
};
operator () (unsigned int val)
,您缺少一组括号。
std::sort()
或),这是完全合理的事情std::for_each()
。
auto
用来声明变量。Stroustrup给出了示例:function<void(char*b, char*e)> rev=[](char*b, char*e) { if( 1<e-b ) { swap( *b, *--e); rev(++b,e); } };
反转给定开始和结束指针的字符串。
没有。
你想做什么?
解决方法:
int main(void)
{
struct foo
{
void operator()() { int a = 1; }
};
foo b;
b(); // call the operator()
}
从C ++ 11开始,您可以使用适当的lambda。有关更多详细信息,请参见其他答案。
旧答案:可以,但是,您必须作弊并使用虚拟类:
void moo()
{
class dummy
{
public:
static void a() { printf("I'm in a!\n"); }
};
dummy::a();
dummy::a();
}
正如其他人提到的,您可以通过使用gcc中的gnu语言扩展来使用嵌套函数。如果您(或您的项目)坚持使用gcc工具链,则您的代码将可以在gcc编译器针对的不同体系结构中移植。
但是,如果可能需要您使用其他工具链来编译代码,那么我将远离此类扩展。
使用嵌套函数时,我也会小心翼翼。它们是管理复杂但有凝聚力的代码块(这些代码块不供外部/通用使用)的优美解决方案。它们在控制名称空间污染方面也非常有帮助(自然复杂/详细语言中的长类。)
但是像其他任何东西一样,它们可能容易受到虐待。
令人遗憾的是C / C ++不支持这些功能作为标准。大多数pascal变体和Ada都可以(几乎所有基于Algol的语言都可以)。与JavaScript相同。与Scala等现代语言相同。与诸如Erlang,Lisp或Python之类的古老语言相同。
而且,与C / C ++一样,不幸的是,Java(我靠自己的大部分时间来谋生)没有。
我在这里提到Java是因为我看到一些张贴者建议使用类和类的方法来替代嵌套函数。这也是Java中的典型解决方法。
简短答案:不可以。
这样做往往会在类层次结构上引入人为的,不必要的复杂性。在所有条件都相等的情况下,理想的做法是使一个类层次结构(及其包含的名称空间和范围)尽可能简单地表示一个实际域。
嵌套函数有助于处理函数内部的“私有”复杂性。缺乏这些设施,就应该避免将这种“私人”复杂性传播到自己的班级模型中。
在软件(以及任何工程学科)中,建模是权衡的问题。因此,在现实生活中,这些规则(或更确切地说是准则)将有合理的例外。不过请谨慎行事。
您不能在C ++中使用本地函数。但是,C ++ 11具有lambdas。Lambda基本是像函数一样工作的变量。
Lambda具有类型std::function
(实际上并不是很正确,但是在大多数情况下可以假设是)。要使用此类型,您需要#include <functional>
。std::function
是一个模板,使用语法将返回类型和参数类型作为模板参数std::function<ReturnType(ArgumentTypes)
。例如,std::function<int(std::string, float)>
一个lambda返回an int
并接受两个参数,一个std::string
和一个float
。最常见的是std::function<void()>
,它什么也不返回,也不接受任何参数。
一旦声明了lambda,就可以像普通函数一样使用以下语法对其进行调用 lambda(arguments)
。
要定义lambda,请使用语法[captures](arguments){code}
(还有其他方法可以执行此操作,但在此不再赘述)。arguments
是lambda接受的参数,code
是调用lambda时应运行的代码。通常,您放置[=]
或[&]
捕获。[=]
意味着您将捕获由value定义值的范围内的所有变量,这意味着它们将保留声明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;
}
您也可以通过指定特定变量的名称来捕获它们。仅指定它们的名称将按值捕获它们,而在&
前面指定它们的名称将按引用捕获它们。例如,[=, &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;
}
您不能更改在lambda内由value捕获的变量的值(由value捕获的变量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;
}
同样,调用未初始化的lambda是未定义的行为,通常会导致程序崩溃。例如,永远不要这样做:
std::function<void()> lambda;
lambda(); //Undefined behavior because lambda is uninitialized
例子
这是您要使用lambdas在问题中要做的代码:
#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;
}
这是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;
}
不,这是不允许的。默认情况下,C和C ++都不支持此功能,但是TonyK指出(在注释中)GNU C编译器的扩展可以在C中启用此功能。
所有这些技巧都(或多或少)只是将其视为局部函数,但它们并非如此。在局部函数中,可以使用其超级函数的局部变量。这是半全球性的。这些技巧都不能做到这一点。最接近的是c ++ 0x的lambda技巧,但是它的关闭是在定义时间而不是使用时间中进行的。
让我在这里发布我认为最干净的C ++ 03解决方案。*
#define DECLARE_LAMBDA(NAME, RETURN_TYPE, FUNCTION) \
struct { RETURN_TYPE operator () FUNCTION } NAME;
...
int main(){
DECLARE_LAMBDA(demoLambda, void, (){ cout<<"I'm a lambda!"<<endl; });
demoLambda();
DECLARE_LAMBDA(plus, int, (int i, int j){
return i+j;
});
cout << "plus(1,2)=" << plus(1,2) << endl;
return 0;
}
(*)在C ++世界中使用宏从未被认为是干净的。
但是我们可以在main()中声明一个函数:
int main()
{
void a();
}
尽管语法是正确的,但有时可能会导致“最烦人的解析”:
#include <iostream>
struct U
{
U() : val(0) {}
U(int val) : val(val) {}
int val;
};
struct V
{
V(U a, U b)
{
std::cout << "V(" << a.val << ", " << b.val << ");\n";
}
~V()
{
std::cout << "~V();\n";
}
};
int main()
{
int five = 5;
V v(U(five), U());
}
=>没有程序输出。
(仅在编译后发出Clang警告)。