我的意思是:
int main()
{
void a()
{
// code
}
a();
return 0;
}
答案 0 :(得分:245)
出于所有意图和目的,C ++通过lambdas支持这一点: 1
int main() {
auto f = []() { return 42; };
std::cout << "f() = " << f() << std::endl;
}
这里,f
是一个lambda对象,在main
中充当本地函数。可以指定Captures以允许函数访问本地对象。
在幕后,f
是function object(即提供operator()
的类型的对象)。函数对象类型由编译器基于lambda创建。
1 ,因为C ++ 11
答案 1 :(得分:179)
在当前版本的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还可以通过** 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 ++不直接支持。
那就是说,你可以拥有本地类,并且它们可以有函数(非static
或static
),所以你可以在一定程度上得到这个,尽管它有点像kludge:
int main() // it's int, dammit!
{
struct X { // struct's as good as class
static void a()
{
}
};
X::a();
return 0;
}
但是,我会质疑实践。每个人都知道(好吧,现在你做了,无论如何:)
)C ++不支持本地函数,所以他们习惯没有它们。但是,它们并没有被用于那个kludge。我会在这段代码上花一点时间来确保它只是允许本地函数。不好。
答案 2 :(得分:39)
已经提到了本地类,但是这里有一种方法可以让它们更像本地函数,使用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';
}
我不建议使用它,这只是一个有趣的技巧(可以做,但imho不应该)。
随着C ++ 11的兴起,您现在可以拥有本地函数,其语法有点像JavaScript的回忆:
auto fac = [] (unsigned int val) {
return val*42;
};
答案 3 :(得分:15)
没有
你想做什么?
解决方法:
int main(void)
{
struct foo
{
void operator()() { int a = 1; }
};
foo b;
b(); // call the operator()
}
答案 4 :(得分:12)
旧答案:你可以,但是你必须作弊并使用虚拟课程:
void moo()
{
class dummy
{
public:
static void a() { printf("I'm in a!\n"); }
};
dummy::a();
dummy::a();
}
更新的答案:较新版本的C ++也支持lambdas更好/正确地执行此操作。查看页面上方的答案。
答案 5 :(得分:7)
不,这是不允许的。默认情况下,C和C ++都不支持此功能,但TonyK指出(在注释中)GNU C编译器有扩展,可以在C中启用此行为。
答案 6 :(得分:7)
正如其他人所提到的,您可以通过在gcc中使用gnu语言扩展来使用嵌套函数。如果您(或您的项目)坚持使用gcc工具链,那么您的代码将主要在gcc编译器所针对的不同体系结构中移植。
但是,如果可能需要使用不同的工具链编译代码,那么我将远离这些扩展。
使用嵌套函数时我也会小心谨慎。它们是一个很好的解决方案,用于管理复杂但有凝聚力的代码块(其中的部分不适用于外部/一般用途。)它们在控制命名空间污染方面也非常有用(对于自然复杂的/非常真实的关注/冗长语言的长课。)
但与任何事情一样,他们可能会被滥用。
令人遗憾的是,C / C ++不支持标准等功能。大多数pascal变种和Ada都做(几乎所有基于Algol的语言都有)。与JavaScript相同。与Scala等现代语言相同。与Erlang,Lisp或Python等古老语言相同。
就像使用C / C ++一样,不幸的是,Java(我的大部分生活都是如此)并没有。
我在这里提到Java因为我看到几张海报建议使用类和类'方法作为嵌套函数的替代。这也是Java中的典型解决方法。
简答:否。
这样做往往会在类层次结构中引入人为的,不必要的复杂性。在所有条件相同的情况下,理想的是使类层次结构(及其包含的名称空间和范围)尽可能简单地表示实际域。
嵌套函数有助于处理“私有”,函数内复杂性。缺乏这些设施,人们应该尽量避免将“私人”复杂性传播到一个人的模型中。
在软件(以及任何工程学科)中,建模是一个权衡问题。因此,在现实生活中,这些规则(或指导方针)将有合理的例外。但是要小心。
答案 7 :(得分:6)
您无法在C ++中定义另一个自由函数。
答案 8 :(得分:5)
所有这些技巧只是看(或多或少)作为本地函数,但它们并不像那样工作。在本地函数中,您可以使用它的超级函数的局部变量。这是半全局的。没有这些技巧可以做到这一点。最接近的是来自c ++ 0x的lambda技巧,但是它的闭包是在定义时间中绑定的,而不是使用时间。
答案 9 :(得分:5)
您不能在C ++中使用本地函数。但是,C ++ 11有lambdas。 Lambdas基本上就像函数一样工作。
lambda的类型为std::function
(actually that's not quite true,但在大多数情况下,您可以认为它是)。要使用此类型,您需要#include <functional>
。 std::function
是一个模板,将返回类型和参数类型作为模板参数,语法为std::function<ReturnType(ArgumentTypes)
。例如,std::function<int(std::string, float)>
是一个lambda返回一个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捕获的变量在lambda中具有const
类型)。为此,您需要通过引用捕获变量。这是一个例子:
#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;
}
答案 10 :(得分:3)
让我在这里为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 ++世界中的(*)从未被认为是干净的。
答案 11 :(得分:2)
但我们可以在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());
}
=&GT;没有节目输出。
(编译后只有Clang警告。)
答案 12 :(得分:0)
当您尝试在另一个函数体中实现一个函数时,必须将此error
作为非法定义:
error C2601: 'a' : local function definitions are illegal
IntelliSense: expected a ';'
所以不要再试一次。