Podemos ter funções dentro de funções?

Quero dizer algo como:

int main() { void a() { // code } a(); return 0; } 

Não, o C ++ não suporta isso.

Edit: Esta resposta é antiga. Enquanto isso, C + + 11 tem lambdas que podem alcançar um resultado similar – veja as respostas abaixo.

Dito isto, você pode ter classs locais, e elas podem ter funções (não static ou static ), então você pode conseguir isso de alguma forma, embora seja um pouco complicado:

 int main() // it's int, dammit! { struct X { // struct's as good as class static void a() { } }; X::a(); return 0; } 

No entanto, eu questionaria a práxis. Todo mundo sabe (bem, agora que você faz, de qualquer maneira :) ) C + + não suporta funções locais, então eles estão acostumados a não tê-los. Eles não são usados, no entanto, para esse kludge. Eu gastaria um bom tempo nesse código para ter certeza de que ele está realmente lá apenas para permitir funções locais. Não é bom.

Para todos os efeitos, o C ++ suporta isso via lambdas : 1

 int main() { auto f = []() { return 42; }; std::cout << "f() = " << f() << std::endl; } 

Aqui, f é um object lambda que atua como uma function local no main . Capturas podem ser especificadas para permitir que a function acesse objects locais.

Nos bastidores, f é um object de function (ou seja, um object de um tipo que fornece um operator() ). O tipo de object de function é criado pelo compilador com base no lambda.


1 desde C ++ 11

Classes locais já foram mencionadas, mas aqui está uma maneira de deixá-las aparecer ainda mais como funções locais, usando uma sobrecarga operator () e uma class anônima:

 int main() { struct { unsigned int operator() (unsigned int val) const { return val<=1 ? 1 : val*(*this)(val-1); } } fac; std::cout << fac(5) << '\n'; } 

Eu não aconselho em usar isso, é apenas um truque engraçado (pode fazer, mas imho não deveria).


Atualização de 2014:

Com o surgimento do C ++ 11 um tempo atrás, agora você pode ter funções locais cuja syntax é um pouco reminiscente de JavaScript:

 auto fac = [] (unsigned int val) { return val*42; }; 

Não.

O que você está tentando fazer?

solução alternativa:

 int main(void) { struct foo { void operator()() { int a = 1; } }; foo b; b(); // call the operator() } 

Resposta antiga: Você pode, meio que, mas você tem que trapacear e usar uma class falsa:

 void moo() { class dummy { public: static void a() { printf("I'm in a!\n"); } }; dummy::a(); dummy::a(); } 

Resposta mais recente: As versões mais recentes do C ++ também suportam o lambdas para fazer isso melhor / corretamente. Veja as respostas mais acima na página.

Não, não é permitido. Nem C nem C ++ suportam este recurso por padrão, entretanto TonyK aponta (nos comentários) que existem extensões para o compilador C GNU que habilitam este comportamento em C.

Você não pode definir uma function livre dentro de outra em C ++.

Como outros já mencionaram, você pode usar funções aninhadas usando as extensões de linguagem gnu no gcc. Se você (ou seu projeto) aderir ao conjunto de ferramentas do gcc, seu código será mais portável entre as diferentes arquiteturas visadas pelo compilador gcc.

No entanto, se houver um possível requisito de que você precise compilar o código com um conjunto de ferramentas diferente, eu ficaria longe de tais extensões.


Eu também trilhar com cuidado ao usar funções aninhadas. Eles são uma bela solução para gerenciar a estrutura de blocos complexos e coesos de código (os quais não são destinados ao uso externo / geral). Eles também são muito úteis no controle da poluição do namespace (uma preocupação muito real com a complexidade natural / classs longas em idiomas verbose.)

Mas, como qualquer coisa, eles podem estar abertos ao abuso.

É triste que o C / C ++ não suporte tais resources como um padrão. A maioria das variantes pascal e Ada do (quase todas as linguagens baseadas em Algol). O mesmo com o JavaScript. O mesmo com idiomas modernos como o Scala. Mesmo com linguagens veneráveis ​​como Erlang, Lisp ou Python.

E, assim como acontece com o C / C ++, infelizmente, o Java (com o qual eu ganho a maior parte da minha vida) não.

Menciono Java aqui porque vejo vários pôsteres sugerindo o uso de classs e methods de class como alternativas para funções aninhadas. E essa é também a solução típica em Java.

Resposta curta: Não.

Fazê-lo tendem a introduzir uma complexidade artificial e desnecessária em uma hierarquia de classs. Com todas as coisas sendo iguais, o ideal é ter uma hierarquia de classs (e seus namespaces e escopos abrangentes) representando um domínio real da forma mais simples possível.

As funções aninhadas ajudam a lidar com a complexidade “privada” dentro da function. Na falta dessas instalações, deve-se tentar evitar a propagação dessa complexidade “privada” para o modelo de class de alguém.

No software (e em qualquer disciplina de engenharia), a modelagem é uma questão de trade-offs. Assim, na vida real, haverá exceções justificadas a essas regras (ou melhor, diretrizes). Proceda com cuidado, no entanto.

Todos esses truques só olham (mais ou menos) como funções locais, mas eles não funcionam assim. Em uma function local, você pode usar variables ​​locais de suas super funções. É uma espécie de semi-globals. Nenhum desses truques pode fazer isso. O mais próximo é o truque do lambda do c ++ 0x, mas o fechamento está ligado no tempo de definição, não no tempo de uso.

Você não pode ter funções locais em C ++. No entanto, o C ++ 11 possui lambdas . Lambdas são basicamente variables ​​que funcionam como funções.

Um lambda possui o tipo std::function ( na verdade, isso não é bem verdade , mas na maioria dos casos você pode supor que é). Para usar esse tipo, você precisa #include . std::function é um template, tomando como argumento template o tipo de retorno e os tipos de argumentos, com a syntax std::function . Por exemplo, std::function é um lambda que retorna um int e recebe dois argumentos, um std::string e um float . O mais comum é std::function , que não retorna nada e não aceita argumentos.

Uma vez que um lambda é declarado, é chamado como uma function normal, usando a syntax lambda(arguments) .

Para definir um lambda, use a syntax [captures](arguments){code} (existem outras maneiras de fazer isso, mas não vou mencioná-las aqui). arguments é quais argumentos o lambda toma, e code é o código que deve ser executado quando o lambda é chamado. Normalmente você coloca [=] ou [&] como capturas. [=] significa que você captura todas as variables ​​no escopo em que o valor é definido por valor, o que significa que elas manterão o valor que tinham quando o lambda foi declarado. [&] significa que você captura todas as variables ​​no escopo por referência, o que significa que elas sempre terão seu valor atual, mas se forem apagadas da memory, o programa falhará. aqui estão alguns exemplos:

 #include  #include  int main(){ int x = 1; std::function lambda1 = [=](){ std::cout << x << std::endl; }; std::function 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 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; } 

Você também pode capturar variables ​​específicas especificando seus nomes. Apenas especificando seu nome irá capturá-los por valor, especificando seu nome com um & antes irá capturá-los por referência. Por exemplo, [=, &foo] capturará todas as variables ​​por valor, exceto foo que será capturado por referência, e [&, foo] capturará todas as variables ​​por referência, exceto foo que será capturado por valor. Você também pode capturar apenas variables ​​específicas, por exemplo, [&foo] capturará foo por referência e não capturará outras variables. Você também não pode capturar nenhuma variável usando [] . Se você tentar usar uma variável em um lambda que você não capturou, ela não será compilada. Aqui está um exemplo:

 #include  int main(){ int x = 4, y = 5; std::function 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; } 

Você não pode alterar o valor de uma variável que foi capturada pelo valor dentro de um lambda (as variables ​​capturadas pelo valor têm um tipo const dentro do lambda). Para fazer isso, você precisa capturar a variável por referência. Aqui está um exemplo:

 #include  int main(){ int x = 3, y = 5; std::function 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; } 

Além disso, chamando lambdas não inicializado é o comportamento indefinido e geralmente fará com que o programa trave. Por exemplo, nunca faça isso:

 std::function lambda; lambda(); //Undefined behavior because lambda is uninitialized 

Exemplos

Aqui está o código para o que você queria fazer em sua pergunta usando lambdas:

 #include  //Don't forget this, otherwise you won't be able to use the std::function type int main(){ std::function a = [](){ // code } a(); return 0; } 

Aqui está um exemplo mais avançado de um lambda:

 #include  //For std::function #include  //For std::cout int main(){ int x = 4; std::function 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; } 

Deixe-me postar aqui uma solução para o C ++ 03 que considero a mais limpa possível. *

 #define DECLARE_LAMBDA(NAME, RETURN_TYPE, FUNCTION) \ struct { RETURN_TYPE operator () FUNCTION } NAME; ... int main(){ DECLARE_LAMBDA(demoLambda, void, (){ cout<<"I'm a lambda!"<
		      	

Mas podemos declarar uma function dentro de main ():

 int main() { void a(); } 

Embora a syntax esteja correta, às vezes ela pode levar à “análise mais problemática”:

 #include  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()); } 

=> sem saída do programa.

(Apenas o aviso Clang após a compilation).

A mais problemática de C ++ novamente

Quando você tenta implementar uma function em outro corpo de function, é necessário obter esse error como definição Ilegal:

 error C2601: 'a' : local function definitions are illegal IntelliSense: expected a ';' 

Então não tente novamente.