¿Hay algún uso para declaraciones de funciones locales?

La mayoría de los progtwigdores de C ++ como yo han cometido el siguiente error en algún momento:

class C { /*...*/ }; int main() { C c(); // declares a function c taking no arguments returning a C, // not, as intended by most, an object c of type C initialized // using the default constructor. c.foo(); // compiler complains here. //... } 

Ahora, aunque el error es bastante obvio una vez que lo sabes, me pregunto si hay algún uso sensato para este tipo de statement de función local, excepto que puedes hacerlo, especialmente dado que no hay forma de definir dicha función local en el mismo bloquear; tienes que definirlo en otro lugar.

Creo que las clases locales de estilo Java son una característica bastante buena que tiendo a usar a menudo, especialmente el tipo anónimo. Incluso las clases locales de C ++ (que pueden tener funciones miembro definidas en línea) tienen algún uso. Pero esta statement de función local sin definición me parece muy incómoda. ¿Es solo un C-legacy o hay algún caso de uso más profundo del que no tengo conocimiento?

Editar para los no creyentes: C c() no es una statement de puntero a la función.

Este progtwig

 int main() { void g(); cout << "Hello "; g(); return 0; } void g() { cout << "world." << endl; } 

salidas Hello world. Este progtwig

 void fun() { cout << "world." << endl; } int main() { void g(); g = fun; cout << "Hello "; g(); return 0; } 

no comstack gcc se queja:

  error: no se puede convertir 'void () ()' en 'void () ()' en la asignación 

Comeau:

  error: la expresión debe ser un lvalue modificable 

He querido declaraciones de funciones locales en C cuando quería pasarlas como argumentos a alguna otra función. Hago esto todo el tiempo en otros idiomas. La razón es encapsular la implementación de estructuras de datos.

Por ejemplo, defino una estructura de datos, por ejemplo, un árbol o un gráfico, y no quiero exponer los detalles de su implementación interna, por ejemplo, porque tal vez quiera cambiarla o modificarla. Expongo las funciones de acceso y mutador para sus elementos y una función transversal para iterar sobre los elementos. La función transversal tiene como argumento una función que opera en un elemento; la tarea de la función transversal es ejecutar la función de argumento en cada elemento y posiblemente agregar los resultados de alguna manera. Ahora cuando llamo a la función transversal, la función de argumento suele ser alguna operación especializada que depende del estado local y, por lo tanto, debe definirse como una función local. Tener que presionar la función, con las variables que contienen el estado local, afuera para ser global, o en una clase interna creada específicamente para contenerlas, es muy feo. Pero este es un problema que tengo con C y Java, no con C ++.

El único uso que puedo pensar es reducir el scope de las declaraciones de funciones:

 int main() { void doSomething(); doSomething(); return 0; } void otherFunc() { doSomething(); // ERROR, doSomething() not in scope } void doSomething() { ... } 

Por supuesto, hay soluciones mucho mejores para esto. Si necesita ocultar una función, realmente debe reestructurar su código moviendo las funciones a módulos separados para que las funciones que necesitan llamar a la función que desea ocultar estén todas en el mismo módulo. Luego, puede hacer que la función module-local sea declarada estática (el modo C) o poniéndola dentro de un espacio de nombre anónimo (el modo C ++).

Es un prototipo de statement avanzada. Posiblemente, si tiene muchas funciones locales o funciones locales que se llaman entre sí de manera contraria al orden de definición, puede necesitarlo.

El único uso sensato que puedo ver es permitir que solo una función en una unidad de comstackción conozca una función definida en otra unidad de comstackción. Creo que sería un uso razonable, pero es el único en el que puedo pensar, y creo que es excesivo.

Como se dijo en el tercer fragmento de esta respuesta , puede ayudar con el sombreado del scope.

 #include  void c(); // Prototype of a function named ``c'' int main() { c(); // call the function { // additional scoppe needed for C, not for C++ int c = 0; // shadow the c function with ac integer variable c++; { void c(); // hide the c integer variable back with the c function c(); } ++c; } //! return 0; } void c() { printf("Called\n"); } 

No creo que este uso sea útil a menudo y existen posibilidades de que no surja en ningún progtwig bien diseñado.

Todavía creo que esta es la razón más probable para esa función, la definición de funciones últimamente en cuanto a las variables no suena tan bien.

A veces lo hago por la misma razón por la que se nos anima a declarar variables justo antes de su primer uso (y no antes), a saber, para mejorar la legibilidad. (Sí, me doy cuenta de que para las variables es más importante porque te alivia de la necesidad de verificar si la variable se usa antes de lo que crees que es su primer uso). Tener el prototipo (especialmente si está más involucrado que solo c() ) cerca de la invocación de la función mejora la legibilidad. El hecho de que el caso especial C c() sea ​​engañoso para los humanos es desafortunado, pero la idea general de declarar funciones localmente tiene sus méritos.

Por supuesto, esto también se aplica a los nombres de funciones que ya están dentro del scope. ¿Por qué no redeclarar cada función antes de cada uso? Mi respuesta a eso: haz todo con moderación. Demasiado desorden impide la legibilidad (así como la capacidad de mantenimiento — si la firma de la función cambia alguna vez). Por lo tanto, aunque no lo descartaría, a veces es útil declarar funciones localmente.

Si desea diferenciar entre declarar una función que no toma parámetros y crear una instancia de una clase con destructor predeterminado, omita los paréntesis.

 class C { public: void foo() {} }; int main() { // declare function d, taking no arguments, returning fresh C C d(); // instantiate class (leave parenthesis out) C c; c.foo(); // call declared function C goo = d(); return 0; } C d() { C c; // .. return c; }