2013-08-08 11 views
6

Con Mingw 4.7.2, ho una libreria che non si compila a causa di una chiamata a isnan. Il compilatore dice "tutto andrà bene" se uso std::isnan e in effetti riesco a compilare il mio file.Isnan è nello std :: namespace? Più in generale, quando è std: necessario, facoltativo o da evitare?

Ma se controllo here (Edit: ma forse avrei dovuto controllare anche here :-)), il std:: non sembra essere necessario. Se lo aggiungo, il file sarà portatile?

Più in generale, per ogni caso esiste un modo generale per capire quando è necessario inserire std:: (per la portabilità), facoltativo o da evitare?

Modifica

Infatti tra le origini del problema è che ci sono più inclusioni di intestazione, e alcune delle intestazioni inclusi comprendono <cmath>, mentre questo file cpp cerca di includere <math.h> (quando <cmath> è già stato incluso).

+1

Non controllare lì, controllare [qui] (http://en.cppreference.com/w/cpp/numeric/math/isnan). –

+0

@ChristianRau Fondamentalmente in C++ 98 questo non esisteva, e si poteva avere solo prendendo a prestito da C! Interessante! – Antonio

+0

No, è sempre stato così com'è. Quel collegamento semplicemente dovrebbe mostrarti che c'è un grande 'std ::' davanti al nome della funzione. Per coincidenza quella particolare funzione 'isnan' è supportata solo con C++ 11 e non esisteva affatto in C++ 98 (nemmeno nell'intestazione C, che era l'intestazione C89/90 e non l'intestazione C99 che C++ 11 usi). Quindi in un modo si potrebbe prendere in prestito da C, ma non dalla C inclusa in C++, ma da un C99 reale (anche se dovrebbe essere uno strano mix allora). –

risposta

12

Dipende dall'intestazione che si include. Se si include l'intestazione C <math.h> (che è parte di C++, anche se contrassegnata come deprecata), è possibile utilizzare le funzioni C non qualificate, come isnan. Se d'altra parte si include il C++ intestazione <cmath>, si sono solo garantito che porta tutte le funzioni dal <math.h> nella std spazio dei nomi e quindi è necessario qualificarli correttamente, come std::isnan (o utilizzare una sorta di using direttiva) .Purtroppo un'implementazione è consentito ma non richiesta di portare queste funzioni nel namespace globale, anche, quando comprese <cmath> (e quindi è uno dei tanti "funziona sulla mia macchina" -incidences di C++ e la ragione perché molte persone scrivono il codice come hai appena provato a compilare senza successo).

Quindi per riassumere: Entrambi includono <math.h> e utilizzare isnan o includere <cmath> e utilizzare std::isnan, tutto il resto è non portabile. Ovviamente tutto ciò vale anche per qualsiasi altra intestazione C e la sua rispettiva versione C++.

EDIT: Va notato tuttavia, che questa particolare funzione isnan è supportata solo dal C++ 11 e non era disponibile in C++ 98 affatto (che può essere parte della confusione). Ma questo non cambia nulla in questa situazione, perché in C++ 98 né <cmath><math.h> (che era l'intestazione C89/C90 vera e propria e non l'intestazione C99 che include C++ 11) aveva questa funzione, dal momento che re sempre in-sync. Quindi, ciò che questa libreria dalla tua domanda ha probabilmente provato è stato usare C++ 98 mentre prendevi la funzione isnan da una diversa implementazione C99 (che non è un'idea particolarmente buona, poiché potrebbe entrare in conflitto con le parti C89/C90 dell'implementazione C++ , mai nemmeno provato questo però).

+0

Quindi è deprecato! In C++ 98 si dovrebbe usare solo allora? E avere un codice che funzioni sia in C++ 98 che in C++ 11 sarebbe possibile? – Antonio

+0

@Antonio Questo intero problema non ha nulla a che fare con C++ 98 vs C++ 11. È sempre stato come descritto nella mia risposta, indipendentemente dallo standard C++. E sì, le intestazioni di C si chiamano deprecate, ma in pratica questo non significa molto ed è piuttosto una questione di gusti che usi (io per me, essendo piuttosto un anti-C snob e un grande fan dello spamming 'std ::' dappertutto, preferisco le intestazioni C++, comunque). Ma dovresti mantenere la coerenza, naturalmente, altrimenti ti capita di sperimentare tali abilità come hai fatto davvero. –

+0

[questo è stato scritto prima del tuo commento] Guardando Christian Rau commento/link sopra: isnan di '' non dovrebbe nemmeno essere lì in C++ 98 ... E l'unico isnan per C++ 98 sarebbe nel deprecato '', che deve essere chiamato senza 'std ::'. Quindi essere portatili è ... impossibile :) a meno di non dover compilare una compilazione condizionale ingombrante. – Antonio

2

Questo perché isnan proviene da C. L'utilizzo di un diverso tipo di include porterà a risultati diversi. Prendere isnan da C intestazione <math.h> come esempio:

Se si utilizza #include <cmath>, sarà messo in std namespace.

Se si utilizza #include <math.h>, verrà inserito nello spazio dei nomi globale.

C++ 11 D.5 libreria C standard di intestazioni

Ogni C intestazione, ognuno dei quali ha un nome del modulo name.h, si comporta come se ogni nome collocato nello spazio dei nomi libreria standard da l'intestazione cname corrispondente viene posizionata all'interno dell'ambito dello spazio dei nomi globale. Non è specificato se questi nomi siano prima dichiarati o definiti all'interno dello spazio dei nomi (3.3.6) dello spazio dei nomi std e siano quindi iniettati nello scope namespace globale mediante esplicita using-declaration (7.3.3).

[Esempio: l'intestazione fornisce sicuramente le sue dichiarazioni e definizioni all'interno dello spazio dei nomi std. Può anche fornire questi nomi all'interno del namespace globale. L'intestazione fornisce sicuramente le stesse dichiarazioni e definizioni all'interno dello spazio dei nomi globale, proprio come nello standard C. Può anche fornire questi nomi all'interno dello spazio dei nomi std. -end esempio]

5

C non ha alcuna nozione di spazi dei nomi. Quando scrivi #include <math.h>, tutti i nomi dichiarati nell'intestazione entrano nello spazio dei nomi globale e devi scrivere isnan.

C++ ha spazi dei nomi. Eppure, quando si scrive #include <math.h> tutti i nomi dichiarati nell'intestazione andare in namespace globale, ed è necessario scrivere isnan, proprio come in C.

Inoltre, quando si scrivono #include <cmath> tutti i nomi dichiarati nell'intestazione andare nel namespace std, ed è necessario scrivere std::isnan.

Inoltre, C++ implementazioni sono ammessi andare anche nella direzione opposta, con #include <math.h> mettere i nomi in stdnonché nel namespace globale, e con #include <cmath> mettendo i nomi nel namespace globale così come in std. Non fare affidamento su questo; il codice che lo fa non è portatile. Questa è una concessione agli implementatori per semplificare le cose; ciò che significa in realtà è che se si utilizza #include <cmath> non si può presumere che non ci sarà isnan nello spazio dei nomi globale e che se si utilizza #include <math.h> non si può presumere che non ci sarà isnan in std.

+0

Quindi cosa succede se includo * entrambi *? (Osservando questo specifico esempio, avrò un comportamento inconsistente) – Antonio

+2

@Antonio Questo probabilmente dipende dal loro ordine di inclusione dei repective e dalle loro protezioni di inclusione. In breve, * non farlo mai *. –

+0

@ChristianRau Grazie, ho solo bisogno di una risposta autorevole :) (Io non sono lo scrittore della biblioteca) – Antonio

Problemi correlati