2015-07-31 13 views
5

Makro DOMAIN w matematyce.h zderza się z wyliczeniami i ewentualnie innymi typami. Nie wiem, co z tym zrobić.zderzenia makro math.h.

#include <algorithm> 

enum Type { DOMAIN }; 


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

} 

Skompiluj z flagą -std = C++ 11. Wersja tego kodu C99 kompiluje się doskonale:

#include <algorithm> 

enum Type { DOMAIN }; 


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

} 

Sprawdziłem kod źródłowy, a biblioteka jest winna. Algorytm obejmuje stl_algo.h, w których istnieje ifdef:

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

Poniższy kod kompiluje grzywny na 11 kompilatora C++:

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

jest to cecha lub błąd?

EDIT * brudny fix:

#ifdef DOMAIN 
#undef DOMAIN 
#endif 
+1

Makro "DOMAIN"? Skąd to pochodzi? Nie mogę go znaleźć ani w C++ 1z, ani w wersjach C11 .. – dyp

+1

Huh. Wydaje się być związany z 'matherr' funkcji systemu V V, nie C ani C++. Makro '__USE_MISC' jest ustawione (zobacz" features.h "glibc); w przeciwnym razie 'math.h' nie zdefiniowałoby makra' DOMAIN'. Możliwe, że dojdzie do trybu "_ISOC11_SOURCE", aby dezaktywować '_DEFAULT_SOURCE', aby pozbyć się' __USE_MISC'. - Edycja: ... wydaje się być bardziej skomplikowana niż ta – dyp

Odpowiedz

6

To błąd (lub "brodawka", jeśli chcesz być hojny).

Cała reszta tej odpowiedzi odnosi się tylko do nagłówków biblioteki standardowej C GCC i Gnu. Odwołania do strony odnoszą się do systemu linuksowego (ale dodałem linki do man7.org).

Makro DOMAIN pochodzi ze wsparcia System V z math.h. (Patrz man matherr.) Obsługa systemu V jest zwykle włączona poprzez zdefiniowanie makra testowego funkcji _SVID_SOURCE (patrz man feature_test_macros), ale jest włączona wraz z serią innych rozszerzeń, jeśli zdefiniowano _GNU_SOURCE, lub domyślnie, jeśli nie zdefiniowano makr testów właściwości. .

gcc predefiniuje _GNU_SOURCE dla programów w C, jeśli opcja --std zostanie pominięty lub ustawiony na gnu##. Różne opcje --std=c## powodują zdefiniowanie.W związku z tym kompilacja kodu C z pewnym wyraźnym standardem C spowoduje zniesienie rozszerzeń systemu V. Trzeba to zrobić, ponieważ rozszerzenia System V nie są zgodne ze standardami, nawet w przypadku Posix, ponieważ zanieczyszczają globalny obszar nazw. (DOMAIN to tylko jeden z przykładów tego zanieczyszczenia.)

Jednak g++ definiuje _GNU_SOURCE--std=c++## nawet jeśli jest określony, a w konsekwencji rozszerzenia systemu V będzie przemycić. (Dzięki @dyp za link do tej libstdc++ FAQ entry. i tym long and inconclusive discussion from 2001 on the GCC mailing list)

jest brzydki obejście jest utworzenie cech siebie, a następnie 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, nie powinno być to konieczne. Ale tak jest.

+0

@dyp: Fajnie, dodam ten link. Ponadto moje obejście problemu nie działa (z powodu wspomnianego w sekcji FAQ). – rici

+0

@dyp, ponieważ ten wątek pochodzi z 2001 roku, mój tl; dr to "nikt nie dba o to, aby go naprawić". – rici

+0

... jeśli to nadal jest ten sam problem :) ale tak, zgodzili się. – dyp

0

§ 17.6.5.2 [res.on.headers]/1 N4140 mówi:

C++ nagłówek może zawierać inne nagłówki C++. Nagłówek C++ dostarcza deklaracje i definicje, które pojawiają się w jego streszczeniu. Nagłówek C++ pokazany w jego streszczeniu jako zawierający inne nagłówki C++ dostarcza deklaracje i definicje, które pojawiają się w streszczeniach tych innych nagłówków.

Dlatego jest ważne dla <algorithm> do #include <cmath> który wstrzykuje przestępstwa makro stałej w przestrzeni nazw.

Należy jednak pamiętać, że „szybkie i brudne fix” jest niedozwolone przez normę (§ 17.6.4.3.1 [macro.names]/1):

Jednostka tłumaczenie który zawiera normę Nagłówek biblioteki nie ma nazw zadeklarowanych w żadnym nagłówku biblioteki standardowej.

Będziesz musiał wybrać inną nazwę niż DOMAIN dla swojej stałej enum.

+1

Cóż, cytujesz standard C++, ale to makro jest specyficzne dla platformy. W związku z tym wymagania C++ nie mają tutaj zastosowania. –

+0

Standard nie zezwala na 'cmath' do zdefiniowania' DOMAIN', więc nie widzę powodu, dla którego nie powinno to być problemem. :) Należy jednak pamiętać, że "DOMAIN" nie jest jedynym zdefiniowanym makrem. – rici

+0

@rici _ Standard nie zezwala na zdefiniowanie DOMAIN_ przez cmath - nie do końca. Standard C++ nie określa ani nie wymaga zdefiniowania makra 'DOMAIN'. Jednak system operacyjny musi przestrzegać innych standardów oprócz C++, takich jak POSIX. Na przykład. POSIX wymaga, aby 'void *' był kompatybilny ze wskaźnikami funkcji i danych, C++ tego nie wymaga. –