2015-07-31 2 views
5

Макро DOMAIN в math.h сталкивается с перечислениями и, возможно, другими типами. Я не знаю, что с этим делать.math.h macro collisions

#include <algorithm> 

enum Type { DOMAIN }; 


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

} 

Скомпилировать с флагом -std = C++ 11. Версия C99 этого кода компилирует прекрасно, хотя:

#include <algorithm> 

enum Type { DOMAIN }; 


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

} 

Я проверил исходный код и библиотеки виноват. Алгоритм включает в себя stl_algo.h, в котором есть IFDEF:

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

Следующий код компилирует штраф на C++ 11 компилятора:

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

ли это функция или ошибка?

EDIT * загрязнен фикс:

#ifdef DOMAIN 
#undef DOMAIN 
#endif 
+1

«ДОМЕН» макрос? Откуда это происходит? Я не могу найти его ни в C++ 1z, ни в C11 черновиках. – dyp

+1

Huh. Это похоже на функцию 'matherr' System V Unix, а не C или C++. Макрос '__USE_MISC' установлен (см.' Features.h' glibc); иначе 'math.h' не будет определять макрос' DOMAIN'. Возможно, в режиме '_ISOC11_SOURCE' можно отключить' _DEFAULT_SOURCE', чтобы избавиться от '__USE_MISC'. - Редактирование: ... это кажется более сложным, чем это – dyp

ответ

6

Это ошибка (или «бородавка», если вы хотите быть щедрым).

Все остальные ответы относятся только к GCC и стандартным библиотекам библиотеки Gnu. Ссылки на страницы man относятся к системе linux (но я добавил ссылки на man7.org).

Масштаб DOMAIN изготовлен из math.h Система V поддержки. (См. man matherr.) Поддержка системы V обычно разрешается путем определения макроса функции-теста _SVID_SOURCE (см. man feature_test_macros), но она разрешена вместе с множеством других расширений, если определено значение _GNU_SOURCE, или по умолчанию, если макросы функций не определены ,

gcc предопределены _GNU_SOURCE для программ C, если опция --std опущена или установлена ​​в gnu##. Различные опции --std=c## вызывают определение __STRICT_ANSI__.Следовательно, компиляция кода C с некоторым явным стандартом C будет подавлять расширения System V. Это необходимо сделать, поскольку расширения System V не совместимы со стандартами, даже с Posix, поскольку они загрязняют глобальное пространство имен. (DOMAIN является лишь одним из примеров такого загрязнения.)

Однако g++ определяет _GNU_SOURCE, даже если --std=c++## указано, и, следовательно, расширения System V будет проникнуть в систему. (Благодаря @dyp для ссылки на этот libstdc++ FAQ entry. и этим long and inconclusive discussion from 2001 on the GCC mailing list)

Безобразная обходной путь, чтобы настроить функции самостоятельно, а затем 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, это не обязательно. Но вот оно.

+0

@ dyp: Прохладный, я добавлю эту ссылку. Кроме того, мое обходное решение не работает (по той причине, о которой говорится в записи FAQ). – rici

+0

@dyp, так как эта нить с 2001 года, мой tl; dr «никто не заботится об этом». – rici

+0

... если это все та же проблема :), но да, согласился. – dyp

0

§ 17.6.5.2 [res.on.headers]/1 из N4140 говорит:

заголовка C++ может включать в себя другие заголовки C++. Заголовок C++ должен содержать декларации и определения, которые содержатся в его кратком описании. Заголовок C++, показанный в его кратком обзоре, как включающий другие заголовки C++, должен предоставить объявления и определения, которые появляются в кратких отчетах других заголовков.

Поэтому справедливо для <algorithm> к #include <cmath>, который впрыскивает константу обижая макросъемки в пространстве имен.

Заметим, однако, что ваш «быстрый и грязный исправить» отвергается стандартом (§ 17.6.4.3.1 [macro.names]/1):

блок перевода, который включает в себя стандарт заголовок библиотеки не должен #define или #undef имена, объявленные в любом стандартном заголовке библиотеки.

Вы должны выбрать имя, отличное от DOMAIN для постоянной enum.

+1

Ну, вы цитируете стандарт C++, но этот макрос является специфичным для платформы. Следовательно, требования C++ здесь не применяются. –

+0

Стандарт не позволяет 'cmath' определять' DOMAIN', поэтому я не понимаю, почему это должно быть проблемой для его определения. :) Но учтите, что 'DOMAIN' - не единственный макрос. – rici

+0

@rici _ Стандарт не позволяет cmath определять DOMAIN_ - не совсем правильно. Стандарт C++ не определяет или не требует определения макроса 'DOMAIN'. Тем не менее, ОС должна следовать другим стандартам в дополнение к C++, таким как POSIX. Например. POSIX требует, чтобы void * 'был совместим с указателями функций и данных, C++ этого не требует. –