funzioni nidificate non sono ammessi, ma il motivo per cui prototipi di funzione annidati sono permessi? [C ++]

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

Domanda

lettura la questione legata che mi porta a questa domanda.

Si consideri il seguente codice

int main()
{
    string SomeString();
}

Tutto dice, compilatore prende questo come un prototipo di funzione e non come un stringa oggetto. Consideriamo ora il seguente codice.

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

Compiler ha detto che questo non è valido come immagino definizione di funzione annidata non è permesso. Se non è consentito, perché i prototipi di funzione annidati sono permessi? non sta dando alcun vantaggio piuttosto che fare confusione (o mi sto perdendo alcuni punti validi qui?).

ho capito vale quanto segue.

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

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

Anche questo è fonte di confusione. Mi aspettavo la funzione somefun () avrà una portata solo in principale . Ma mi sbagliavo. Perché compilatore sta permettendo a compilare il codice come sopra? C'è qualche situazioni in tempo reale in cui il codice come sopra ha senso?

Qualche idea?

È stato utile?

Soluzione

Il prototipo è solo ' dichiarazione anticipata '. Si prega di controllare l'articolo di Wikipedia.

In sostanza, si dice al compilatore "non allarmatevi se l'etichetta 'somefun' viene utilizzato in questo modo". Ma la vostra linker è ciò che è responsabile per la ricerca del corpo della funzione corretta.

Si può effettivamente dichiarare un prototipo di falso, per esempio 'Somefun char ()' e usarlo su tutto il principale. Si otterrà solo un errore quando il linker cerca di trovare il corpo della funzione fasullo. Ma il compilatore sarà fresco con esso.

Ci sono un sacco di benefici. Bisogna ricordare il corpo della funzione non è sempre nello stesso file di codice sorgente. Si può essere in una library.Also collegata, quella libreria collegata può essere hanno uno specifico link' signature'.Use condizionale definisce si può anche selezionare la firma link corretto al momento della compilazione usando le vostre con ambito prototypes.Although maggior parte delle persone avrebbe utilizzato puntatori a funzione per che, invece.

Spero che questo aiuti.

Altri suggerimenti

Come nota a margine, C ++ 03 ha un modo indiretto di definire funzioni locali. Richiede abusando della funzione locale di classe:

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

Questa è una convenzione da C - come molti -. Che C ++ ha adottato

La possibilità di dichiarare una funzione all'interno di un'altra funzione in C è una decisione che la maggior parte dei programmatori probabilmente considerano spiacevole e inutile. In particolare con design moderno orientata agli oggetti in cui le definizioni di funzione sono relativamente più piccole di quanto non siano in C.

Se si desidera avere funzioni che esistono solo nel campo di applicazione di un'altra funzione, due opzioni sono boost :: lambda e C ++ 1x lambda .

Per quanto riguarda il motivo per cui la vostra dichiarazione di

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

è meglio di questo

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

E 'generalmente buona se si mantiene dichiarazioni il più possibile locale, in modo che il minor numero di scontri nome come possibile risultato. Io dico che è discutibile se dichiarare una funzione a livello locale (in questo modo) è davvero fortunati, come penso che sia ancora meglio ordinaria includere il suo colpo di testa e poi il modo in cui "solito", che è anche meno confusione per la gente non sapere a tale proposito. A volte, è utile anche per risolvere una funzione ombra

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

Naturalmente, in C ++ che potremmo chiamare la funzione g usando its_namespace::g() - ma ai vecchi tempi di C, che non sarebbe stato possibile, e che cosa permesso al programmatore di accedere ancora alla funzione. Si noti inoltre che mentre sintatticamente non è la stessa, semanticamente seguente non anche dichiarare una funzione in un ambito locale, che rivolge realtà una portata diversa.

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

Come nota a margine, ci sono più situazioni come quella in cui l'ambito obiettivo di una dichiarazione è non l'ambito in cui questa dichiarazione appare in. In generale, l'entità si dichiara diventa un membro del in cui appare dichiarazione portata. Ma non è sempre il caso. Si consideri ad esempio per le dichiarazioni di amicizia, dove quella cosa succede

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

Anche se la dichiarazione di funzione (e la definizione!) Di f accaduto nell'ambito della X, l'entità (la funzione stessa) è diventato un membro dello spazio dei nomi che racchiude.

prototipi di funzione sono suggerimenti per il compilatore. Essi indicano che le funzioni sono implementate da qualche altra parte, se non è già scoperto . Niente di più.

Quando si dichiara un prototipo, come si sta facendo si sono sostanzialmente dicendo al compilatore di attendere che il linker per risolverlo. A seconda di dove si scrive il prototipo si applicano le regole di scoping. Non c'è nulla di tecnicamente sbagliato a scrivere il prototipo all'interno della vostra funzione main () (anche se secondo me un po 'Messier), significa solo che la funzione è solo localmente conosciuta all'interno del main (). Se si avrebbe dichiarato il prototipo nella parte superiore del file di origine (o più comunemente in un file di intestazione), il prototipo / funzione dovrebbe essere conosciuto in tutta la fonte.

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

int main(int argc,char**argv)
{
   string someString();
   string s = somestring(); // OK
   ...
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top