2015-07-31 11 views
5

Macro DOMAIN in matematica.h si scontra con enumerazioni e possibilmente con altri tipi. Non so cosa farmene.math.h macro collisioni

#include <algorithm> 

enum Type { DOMAIN }; 


int main(){ 
    Type t = Type::DOMAIN; 
    return 0; 

} 

Compilare con flag -std = C++ 11. La versione C99 di questo codice viene compilato perfettamente bene però:

#include <algorithm> 

enum Type { DOMAIN }; 


int main(){ 
    Type t = DOMAIN; 
    return 0; 

} 

Ho controllato il codice sorgente e la biblioteca è da biasimare. algoritmo include stl_algo.h, in cui v'è ifdef:

#if __cplusplus >= 201103L 
#include <random>  // for std::uniform_int_distribution 
#include <functional> // for std::bind 
#endif 

Il seguente codice compila bene su C++ 11 compilatore:

#include <random> 
#include <iostream> 
int main(){ 
    std::cout << DOMAIN << std::endl; 
    return 0; 
} 

Si tratta di una caratteristica o un bug?

EDIT * fix sporca:

#ifdef DOMAIN 
#undef DOMAIN 
#endif 
+1

La macro 'DOMAIN'? Da dove viene questo? Non riesco a trovarlo né in C++ 1z né in bozze C11 .. – dyp

+1

Huh. Sembra essere correlato alla funzione 'matherr' di System V Unix, non a C né a C++. La macro '__USE_MISC' è impostata (vedere' features.h' di glibc); altrimenti 'math.h' non definirebbe la macro' DOMAIN'. Potrebbe essere possibile accedere alla modalità '_ISOC11_SOURCE' per disattivare' _DEFAULT_SOURCE' per eliminare '__USE_MISC'. - Modifica: ... sembra essere più complicato di quello – dyp

risposta

6

È un bug (o una "verruca" se si vuole essere generosi).

Tutto il resto di questa risposta si riferisce solo a GCC e alle intestazioni della libreria C standard di Gnu. I riferimenti alle pagine man si riferiscono a un sistema Linux (ma ho aggiunto dei collegamenti a man7.org).

La macro DOMAIN viene fornita dal supporto System V math.h. (Vedere man matherr.) Il supporto del sistema V è normalmente abilitato definendo la macro del test delle funzioni _SVID_SOURCE (vedere man feature_test_macros), ma è abilitato insieme a una serie di altre estensioni se _GNU_SOURCE è definito o per impostazione predefinita se non sono definite macro di test delle funzionalità .

gcc pubblicitario predefinito _GNU_SOURCE per programmi C se l'opzione --std viene omesso o impostato a gnu##. Le varie opzioni --std=c## causano la definizione di __STRICT_ANSI__.Di conseguenza, la compilazione del codice C con alcuni standard C espliciti sopprimerà le estensioni System V. Questo deve essere fatto perché le estensioni del System V non sono compatibili con gli standard, nemmeno con Posix, perché inquinano lo spazio dei nomi globale. (DOMAIN è solo un esempio di questo inquinamento.)

Tuttavia, g++ definisce _GNU_SOURCE anche se --std=c++## è specificato, e di conseguenza le estensioni System V sarà furtivamente. (Grazie a @dyp per il collegamento a questo libstdc++ FAQ entry. e questo long and inconclusive discussion from 2001 on the GCC mailing list)

Un brutto soluzione è quella di impostare le funzioni di te stesso, e poi undefine __USE_SVID:

#include <features.h> 
#undef __USE_SVID 

#include <random> 
#include <iostream> 

int main(){ 
    std::cout << DOMAIN << std::endl; 
    return 0; 
} 

(Live on coliru)

IMHO, questo non dovrebbe essere necessario. Ma eccolo.

+0

@dyp: Cool, aggiungerò quel collegamento. Inoltre, la mia soluzione alternativa non funziona (per il motivo accennato nella voce FAQ). – rici

+0

@ dyp, dal momento che quel thread è del 2001, il mio tl; dr è "nessuno si preoccupa abbastanza di risolverlo". – rici

+0

... se questo è ancora lo stesso problema :) ma sì, d'accordo. – dyp

0

§ 17.6.5.2 [res.on.headers]/1 di N4140 dice:

A C++ intestazione può includere altre intestazioni C++. Un'intestazione C++ deve fornire le dichiarazioni e le definizioni che appaiono nella sua sinossi. Un'intestazione C++ mostrata nella sinossi come comprendente altri header C++ deve fornire le dichiarazioni e le definizioni che appaiono nelle sinossi di quelle altre intestazioni.

Pertanto, è valido per <algorithm> a #include <cmath> che inietta l'incriminato macro costante nel vostro spazio dei nomi.

Si noti, tuttavia, che il “quick fix e sporco” non è consentita dallo standard (§ 17.6.4.3.1 [macro.names]/1):

Un'unità di traduzione che include uno standard l'intestazione della libreria non deve essere #define o #undef nomi dichiarati in qualsiasi intestazione di libreria standard.

Dovrete scegliere un nome diverso da DOMAIN per il vostro enum costante.

+1

Bene, si cita lo standard C++, ma questa macro è specifica della piattaforma. Quindi, i requisiti C++ non si applicano qui. –

+0

Lo standard non permette a 'cmath' di definire' DOMINIO', quindi non vedo perché dovrebbe essere un problema undefinirlo. :) Ma nota che 'DOMAIN' non è l'unica macro definita. – rici

+0

@rici _Lo standard non consente al cmath di definire DOMAIN_ - non proprio a destra. Lo standard C++ non specifica o richiede che venga definito il 'DOMINIO 'della macro. Tuttavia, il sistema operativo deve seguire altri standard oltre a C++, come POSIX. Per esempio. POSIX richiede che 'void *' sia compatibile con i puntatori di funzioni e dati, il C++ non richiede questo. –