我们可以在函数内部有函数吗?
我的意思是这样的:
int main() { void a() { // code } a(); }
不,C ++不支持。
编辑:这个答案是旧的。 同时,C ++ 11的lambdas可以达到类似的结果 – 请参阅下面的答案。
也就是说,你可以有本地类,它们可以有函数(非static
或static
),所以你可以在一定程度上得到这个,尽pipe它有点混乱:
int main() // it's int, dammit! { struct X { // struct's as good as class static void a() { } }; X::a(); return 0; }
但是,我会质疑这个实践。 每个人都知道(好吧,现在你是这样做了:)
)C ++不支持本地函数,所以它们习惯于不拥有它们。 然而,他们并没有使用这个kludge。 我会在这段代码上花费相当长的时间,以确保它只是在那里允许本地函数。 不好。
C ++ 11使用lambdas / closures支持这个。
int main() { auto f = []() { return 42; }; std::cout << "f() = " << f() << std::endl; }
在GCC和clang的最新版本中,可以通过将-std=c++11
标志传递给编译器来testing。
本地类已经被提到,但是这里有一种方法可以让它们更像本地函数,使用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'; }
我不build议使用这个,这只是一个有趣的技巧(可以做,但imho不应该)。
2014更新:
随着C ++ 11的兴起,你现在可以拥有一些本地函数,它们的语法有点像JavaScript一样:
auto fac = [] (unsigned int val) { return val*42; };
没有。
你想做什么?
解决方法:
int main(void) { struct foo { void operator()() { int a = 1; } }; foo b; b(); // call the operator() }
你可以,sorting,但你必须作弊和使用虚拟类:
void moo() { class dummy { public: static void a() { printf("I'm in a!\n"); } }; dummy::a(); dummy::a(); }
不,这是不允许的。 C和C ++在默认情况下都不支持这个特性,不过TonyK指出(在注释中)GNU C编译器有一些扩展,在C中启用了这种行为。
你不能在C ++中定义一个自由函数。
正如其他人所提到的,你可以使用gcc中的gnu语言扩展来使用嵌套函数。 如果您(或您的项目)坚持使用gcc工具链,那么您的代码将主要在gcc编译器所针对的不同体系结构中移植。
但是,如果有可能需要您可能需要用不同的工具链编译代码,那么我会远离这样的扩展。
使用嵌套函数时,我也会小心谨慎。 它们是pipe理复杂但内聚的代码块的结构的一个美丽的解决scheme(这些块不是为了外部/一般的使用)。它们在控制命名空间污染方面也非常有帮助(对自然复杂/冗长的课程在冗长的语言。)
但是就像任何事情一样,他们可能会被滥用。
C / C ++不支持标准这样的function是很可悲的。 大多数帕斯卡变种和阿达(几乎所有的Algol为基础的语言)。 与JavaScript相同。 与Scala等现代语言一样。 与Erlang,Lisp或Python等古老的语言一样。
和C / C ++一样,不幸的是,Java(我赢得了大部分生活)并不是。
我在这里提到Java,因为我看到几个海报build议使用类和类的方法作为嵌套函数的替代方法。 这也是Java中的典型解决方法。
简短的回答:不。
这样做往往会在类层次上引入人为的,不必要的复杂性。 在所有条件都相同的情况下,理想的是让一个类层次结构(及其包含的名称空间和范围)尽可能简单地表示一个实际的域。
嵌套函数有助于处理“私人”的function内复杂性。 缺乏这些设施,应该尽量避免将这种“私人”的复杂性传播到一个class级的模型中。
在软件(和任何工程学科)中,build模是一个权衡的问题。 因此,在现实生活中,这些规则(或者说是指导方针)会有合理的例外。 尽pipe如此,请谨慎行事。
所有这些技巧只是看起来(或多或less)作为本地function,但他们不这样工作。 在本地函数中,你可以使用它的超级函数的局部variables。 这是一种半全球性的。 非这些技巧可以做到这一点。 最接近的是来自c ++ 0x的lambda技巧,但是它的定界时间是closures的,而不是使用时间。
让我发表一个解决scheme在这里为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 ++世界中使用macros从来没有被认为是干净的。
但是我们可以在main()中声明一个函数:
int main() { void a(); }
虽然语法是正确的,但有时会导致“最令人头疼的parsing”:
#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警告)。
C ++最令人烦恼的parsing
你不能在C ++中有本地函数。 但是,C ++ 11有lambdaexpression式 。 Lambdas基本上是像函数一样工作的variables。
一个lambda具有std::function
types( 实际上这不是很正确 ,但在大多数情况下,你可以假设它是)。 要使用这种types,你需要#include <functional>
。 std::function
是一个模板,将模板参数作为返回types和参数types,语法为std::function<ReturnType(ArgumentTypes)
。 例如, std::function<int(std::string, float)>
是一个返回一个int
的lambdaexpression式,接受两个参数,一个std::string
和一个float
。 最常见的是std::function<void()>
,它不返回任何参数。
一旦声明了lambda,就像使用语法lambda(arguments)
的普通函数一样调用它。
要定义一个lambdaexpression式,使用语法[captures](arguments){code}
(还有其他方法可以做,但我不会在这里提到)。 arguments
是lambda采用的参数,而code
是在调用lambda时应该运行的代码。 通常你把[=]
或[&]
作为捕捉。 [=]
意味着你捕获值的范围内的所有variables值,这意味着他们将保持他们的lambda声明时的值。 [&]
意味着你通过引用来捕获范围内的所有variables,这意味着它们将始终具有它们的当前值,但是如果从内存中删除,则程序将崩溃。 这里有些例子:
#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; }
您也可以通过指定其名称来捕获特定的variables。 只要指定他们的名字就可以捕获它们的价值,用&
前面的名字指定他们的名字将通过引用捕获它们。 例如, [=, &foo]
将通过值捕获所有的variables,除了将被引用捕获的foo
外, [&, foo]
将捕获所有的variables,除了将被值捕获的foo
。 您也可以只捕获特定的variables,例如[&foo]
将通过引用捕获foo
,并且不会捕获其他variables。 您也可以通过使用[]
来捕获任何variables。 如果你试图在你没有捕获的lambda中使用一个variables,它将不会被编译。 这里是一个例子:
#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内由值捕获的variables的值(由值捕获的variables在lambda内具有const
types)。 为此,您需要通过引用捕获variables。 这里是一个例子:
#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; }
另外,调用未初始化的lambdas是未定义的行为,通常会导致程序崩溃。 例如,从来没有这样做:
std::function<void()> lambda; lambda(); //Undefined behavior because lambda is uninitialized
例子
这里是你想要在你的问题中使用lambdaexpression式的代码:
#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; }