Can we have functions inside functions in C++?
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:
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:
With the rise of C++11 a while back, you can now have local functions whose syntax is a little reminiscient of JavaScript:
auto fac = [] (unsigned int val) {
return val*42;
};
For a recursive function, compile-time type deduction is not supported:
function<int(int)> factorial{ [&](int n)
{
return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
} };
For all intents and purposes, C++ supports this via 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.
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.
1 since C++11
You can't have local functions in C++. However, C++11 has lambdas. Lambdas are basically variables that work like functions.
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.
Once a lambda is declared, it is called just like a normal function, using the syntax 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:
#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 reference 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:
#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:
#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:
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:
#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:
#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;
}
Modern C++ - Yes with 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:
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.
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++ doesn't support that directly.
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:
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.