2015-12-28 11 views
6

Sto leggendo "Il linguaggio di programmazione C++ - Quarta edizione" e stavo scrivendo un semplice esercizio solo per ottenere un blocco della sintassi C++ e per sbaglio mi sono imbattuto in qualcosa che mi ha fatto alzare un sopracciglio. In breve, ho dimenticato di aggiungere () su accept nella principale:Avviso chiamata mancata lista argomento chiamata

bool accept() 
{ 
    cout << "Do you want to proceed (y or n)?\n"; 

    char answer = 0; 
    cin >> answer; 

    if (answer == 'y') 
    { 
     return true; 
    } 
    return false; 

} 

int main() 
{ 
    accept; 
} 

Questo corre e compilazione e produce (in VS2015) un

C4551 - lista degli argomenti funzione di chiamata mancante

Mi sono trovato a leggere e una serie di domande su SO che dovrebbero essere chiuse perché in genere chiedono di "eseguire il debug del mio codice".

Ho pensato che se il codice viene compilato ed eseguito, e la funzione contiene un'istruzione di blocco (in attesa di input dell'utente) e un tipo di ritorno, che tutto il codice verrebbe eseguito come previsto a prescindere dalla mancanza delle parentesi; non è questo il caso però.

Inoltre, ho pensato che vorrei cambiare la chiamata a accept in principale, per bool a = accept; cout << a; per cercare di prevenire qualsiasi ottimizzazione (se questo era quello che stava realmente accadendo), e che non ho chiamato il codice accept() sia.

Cosa Sono curioso di sapere è:

  1. Qual è la chiamata a farsi accept compilato in?
  2. Perché non è il codice in accept sempre chiamato
  3. Perché questo è solo un avviso, e non un errore (So di poter cambiare la configurazione per visualizzarla come errore, io sono più in modo da mettere in discussione come questo è accettato sintassi per impostazione predefinita quando il risultato effettivo differisce dal risultato previsto in modo "drammatico?" Questa domanda potrebbe essere basata sull'opinione pubblica, ometterla se si è d'accordo.)
  4. L'esecuzione del codice bool a = accept; cout << a; nella principale produce 1 come output. Come può essere questo quando false è il valore bool predefinito (almeno in C#) e non c'è nulla per restituire un valore vero poiché il codice di accettazione non viene eseguito?
+2

Eventuali duplicati di [Perché l'compilatore C++ si lamentano quando uso le funzioni senza parentesi?] (Http://stackoverflow.com/questions/11082329/why-doesnt-the-c-compiler-complain -quando-i-uso-funzioni-senza-parentesi) e http://stackoverflow.com/questions/17073066/g-calling-function-without-parenthesis-not-f-but-f-why-always-return –

+2

@ HithamS.AlQadheeb: Mentre è vicino, chiede un paio di altre cose che hanno a che fare con i puntatori di funzione e decadendo in 'bool'. Quindi non è un duplicato completo. –

+1

@ HithamS.AlQadheeb la risposta nel "duplicato" risponde solo a una parte della mia domanda. Il titolo della domanda "duplicato" è esattamente l'esatto opposto di quello che stavo vivendo, poiché il mio compilatore stava dando l'avvertimento, quindi io usavo il testo di avvertimento come titolo della domanda così è facilmente reperibile nelle ricerche quando gli altri si imbattono nello stesso avvertimento. Le altre domande che usano il mio stesso titolo chiedono "perché il mio codice non funziona", quindi potrebbe essere più utile chiuderle contro chi chiude la mia Q quando il "dupe" che hai trovato è (beh non è un capriccio, e) a malapena ricercabile. – Kcvin

risposta

14
  1. Nessuna "chiamata a accept". Vedi # 3.

  2. A causa di # 1.

  3. L'utilizzo di un nome di funzione senza sintassi della funzione di chiamata (es: ()) significa che si sta accedendo alla funzione stessa. Si potrebbe, per esempio, conservarlo in un puntatore a funzione (attraverso la funzione-to-pointer in decomposizione):

    using my_func = bool(*)(); //Function that takes nothing and returns a bool. 
    my_func var = accept; //Store a pointer to `accept`. 
    

    Si potrebbe quindi emettere var();, che avrebbe chiamato accept.

    Tuttavia, poiché non si memorizza mai la funzione, il compilatore indovina che probabilmente si è inteso a chiamare la funzione, per non accedere al puntatore della funzione. accept; tuttavia è un'istruzione C++ legale, pertanto il compilatore non può commettere errori. Può emettere un avvertimento, poiché l'affermazione non porta a nulla e probabilmente intendevi chiamare la funzione. Non è diverso da una dichiarazione come 1;: perfettamente legale, ma assolutamente inutile.

  4. Fa questo a causa del trucco C++. I puntatori non nulli si decompongono sul valore booleano true.E accept decade a un puntatore di funzione che non è nullo. Pertanto, una volta convertito in bool, sarà true. Non sei ancora chiamando il la funzione.

8

In C++, qualsiasi espressione seguita da un punto e virgola è un'istruzione legale. (Perché? Perché C ti faccio fare questo, penso). Ciò significa che tutte le seguenti sono le dichiarazioni legali:

5; 
3 + 5; 
1 % 2 == 0; 

L'effetto di una dichiarazione di questa forma è che l'espressione viene valutata e poi scartata. Un buon compilatore di ottimizzazione eliminerebbe semplicemente tutta la logica qui, poiché nessuno di questi ha effetti collaterali.

Nel tuo caso, scrivendo

accept; 

è una dichiarazione legale perché accept è una valutazione di espressione per un riferimento alla funzione accept. Ciò significa che accept; significa "valutare l'indirizzo di accept, quindi scartarlo". Il motivo per cui nessuna funzione è chiamata qui è che un nome di funzione di per sé non invoca la funzione; hai bisogno delle parentesi (l'operatore di chiamata di funzione) per effettuare effettivamente la chiamata.Ciò è utile, ad esempio, se si desidera passare una funzione in un'altra funzione. Ad esempio, si potrebbe desiderare di passare una funzione di confronto in std::sort, in questo modo:

std::sort(range.begin(), range.end(), nameOfMyComparisonFunction) 

Qui, sarebbe un vero problema se questo provato a chiamare nameOfMyComparisonFunction, dal momento che gli argomenti non possono essere conosciuti fino a quando la routine di ordinamento inizia.

Quindi, perché questo è un avviso e non un errore? Bene, è un codice C++ perfettamente legale, quindi il compilatore non può definirlo un errore. Tuttavia, il compilatore ha ragione a contrassegnarlo come un avvertimento, poiché quasi certamente significa che hai fatto un errore. Detto questo, la maggior parte dei compilatori ha alcune impostazioni che segnalano gli errori come errori e se si alza il livello di avviso abbastanza alto il compilatore probabilmente direbbe dire "questo è così sospetto che ho intenzione di assumere che hai incasinato qualcosa".

Per quanto riguarda il tuo ultimo - perché fa

bool a = accept; 

finiscono impostazione a-true? In C++, qualsiasi puntatore non nullo converte implicitamente alla vera e qualsiasi puntatore nullo converte implicitamente su false. In C++, le funzioni sono implicitamente convertibili in puntatori a se stessi, quindi in questo caso accept valuta l'indirizzo della funzione accept, che non è nulla, quindi imposta a su true. Quando poi scrivere

cout << a << endl; 

il valore viene stampato come 1, perchè bool valori vengono stampati come 1 e 0, piuttosto che true e false per impostazione predefinita. Detto questo, si potrebbe scrivere

cout << boolalpha << a << endl; 

e vedrete true stampate invece.

Spero che questo aiuti!

Problemi correlati