Funciones anidadas no están permitidos pero ¿por qué se les permite prototipos de funciones anidados? [C ++]

StackOverflow https://stackoverflow.com/questions/928992

Pregunta

estaba leyendo la cuestión vinculada que me lleva a hacer esta pregunta.

Considere el siguiente código

int main()
{
    string SomeString();
}

Todo lo dice, compilador toma esto como un prototipo de función y no como un cadena objeto. Ahora considere el siguiente código.

int main()
{
    string Some()
    {
        return "";
    }
}

Compilador dijo que esto no es válida ya que supongo que no está permitido definición de la función anidada. Si no se permite, ¿por qué prototipos de funciones anidadas se permite? No está dando ninguna ventaja en lugar de hacer la confusión (o me estoy perdiendo algunos puntos válidos aquí?).

Me di cuenta de lo siguiente es válido.

int main()
{ 
  string SomeFun();
  SomeFun();
  return 0;
}

string SomeFun()
{
  std::cout << "WOW this is unexpected" << std::endl;
}

Esto también es confuso. Yo estaba esperando la función SomeFun () tener un alcance sólo en principal . Pero estaba equivocado. ¿Por qué compilador está permitiendo a compilar el código como el de arriba? ¿Hay alguna situación en tiempo real donde el código como el de arriba tiene sentido?

¿Alguna idea?

¿Fue útil?

Solución

Su prototipo es simplemente ' Declaración Adelante '. Por favor, consulte el artículo de Wikipedia.

Básicamente, se le indica al compilador "no se alarme si la etiqueta 'SomeFun' se utiliza de esta manera". Sin embargo, su unión es lo que es responsable de encontrar el cuerpo de la función correcta.

Se puede declarar en realidad un prototipo falso, por ejemplo, 'SomeFun char ()' y usarlo en todo su principal. Sólo se obtendrá un error cuando el enlazador trata de encontrar el cuerpo de su función falso. Pero su compilador estará bien con eso.

Hay un montón de beneficios. Hay que recordar que el cuerpo función no está siempre en el mismo archivo de código fuente. Puede ser en un library.Also vinculado, que la biblioteca puede ser ligado tienen un enlace específico' signature'.Use condicional define incluso se puede seleccionar la firma enlace correcto en tiempo de compilación usando sus prototypes.Although mayoría de las personas con ámbito utilizaría punteros de función para en su lugar.

Espero que esto ayude.

Otros consejos

Así como una nota al margen, C ++ 03 tiene una manera indirecta de la definición de las funciones locales. Requiere abusar de la característica de clase local:

int main()
{
    struct Local
    {
        static string Some()
        {
            return "";
        }
    };
    std::cout << Local::Some() << std::endl;
}

Esta es una convención de C - al igual que muchos -. C ++, que ha adoptado

La posibilidad de declarar una función dentro de otra función en C es una decisión que la mayoría de los programadores probablemente consideran lamentable e innecesario. Particularmente con diseño OOP moderno, donde las definiciones de funciones son comparativamente más pequeña de lo que son en C.

Si le gustaría tener funciones que sólo existen en el ámbito de otra función, hay dos opciones boost :: lambda y C ++ 1x lambda .

En cuanto a por qué su declaración de

void f() {
    void g(); g();
}

es mejor que éste

void g();
void f() {
    g();
}

Por lo general es buena si se mantiene declaraciones lo más local posible, de manera que el menor número de colisiones de nombres como sea posible resultado. Yo digo que es discutible si se declara una función localmente (de esta manera) es realmente suerte, ya que creo que es aún mejor ordinarios incluyen el encabezado y luego ir por el camino "habitual", que también es menos confuso la gente no saber acerca de eso. A veces, también es útil para trabajar en torno a una función de sombreado

void f() {
    int g; 
    // oops, ::g is shadowed. But we can work around that
    {
        void g(); g();
    }
}

Por supuesto, en C ++ que podríamos llamar g función utilizando its_namespace::g() - pero en los viejos tiempos de C, que no habría sido posible, y que lo permitido que el programador todavía acceder a la función. También tenga en cuenta que aunque sintácticamente no es la misma, la siguiente semánticamente no también declarar una función dentro de un ámbito local, que en realidad se dirige a un ámbito diferente.

int main() {
    using std::exit;
    exit();
}

Como nota al margen, hay más situaciones como esa, donde el alcance objetivo de la declaración es no el alcance siempre que la declaración aparece en. En general, la entidad se declara llega a ser miembro de la en el que aparece la declaración de alcance. Pero eso no es siempre el caso. Consideremos, por ejemplo, las declaraciones de amistad, donde esa cosa sucede

struct X { friend void f() { std::cout << "WoW"; } };
int main() { void f(); f(); } // works!

A pesar de que la declaración de función (y definición!) De f ocurrieron dentro del ámbito de X, la entidad (la función en sí) se convirtió en un miembro del espacio de nombres de cerramiento.

Los prototipos de función son consejos para el compilador. Indican que las funciones se implementan en otro lugar, si no está ya descubierto . Nada más.

Cuando se declara un prototipo como lo están haciendo básicamente están diciendo al compilador que esperar a que el enlazador para resolverlo. Dependiendo donde se escribe el prototipo se aplican las reglas de alcance. No hay nada técnicamente mal escrito el prototipo dentro de la función main () (aunque en mi humilde opinión un poco más desordenado), sólo significa que la función se conoce sólo a nivel local dentro de la función main (). Si hubiera declarado el prototipo en la parte superior del archivo fuente (o más comúnmente en un fichero de cabecera), el prototipo / función sería conocido en toda la fuente.

string foo()
{
  string ret = someString();  // Error
  return ret; 
}

int main(int argc,char**argv)
{
   string someString();
   string s = somestring(); // OK
   ...
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top