math.h 宏冲突
math.h macro collisions
math.h 中的宏 DOMAIN
与枚举和可能的其他类型发生冲突。我不知道该怎么做。
#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;
}
这是功能还是错误?
编辑* 脏修复:
#ifdef DOMAIN
#undef DOMAIN
#endif
§ 17.6.5.2 [res.on.headers] / N4140 的 1 说:
A C++ header may include other C++ headers. A C++ header shall provide the declarations and definitions that appear in its synopsis. A C++ header shown in its synopsis as including other C++ headers shall provide
the declarations and definitions that appear in the synopses of those other headers.
因此,<algorithm>
到 #include <cmath>
是有效的,它会将有问题的宏常量注入到您的命名空间中。
但是请注意,标准 (§ 17.6.4.3.1 [macro.names] / 1) 不允许您的“快速修复”:
A translation unit that includes a standard library header shall not #define
or #undef
names declared in any standard library header.
您必须为 enum
常量选择一个不同于 DOMAIN
的名称。
这是一个错误(或者 "wart" 如果你想大方一点)。
此答案的所有其余部分仅涉及 GCC 和 Gnu 标准 C 库头文件。 man
页面引用是 linux 系统(但我已将 link 添加到 man7.org)。
DOMAIN
宏来自 math.h
的 System V 支持。 (参见 man matherr
.) System V support is normally enabled by defining the _SVID_SOURCE
feature-test macro (see man feature_test_macros
),但如果定义了 _GNU_SOURCE
,它会与大量其他扩展一起启用,或者如果未定义功能测试宏,则默认情况下启用。
如果省略 --std
选项或设置为 gnu##
,则 gcc
为 C 程序预定义 _GNU_SOURCE
。各种 --std=c##
选项导致 __STRICT_ANSI__
被定义。因此,使用某些明确的 C 标准编译 C 代码将抑制 System V 扩展。需要这样做是因为 System V 扩展不符合标准,甚至 Posix 也不兼容,因为它们污染了全局命名空间。 (DOMAIN
只是这种污染的一个例子。)
然而,即使指定了 --std=c++##
,g++
也会定义 _GNU_SOURCE
,因此系统 V 扩展将潜入。(感谢@dyp 提供 link对此 libstdc++ FAQ entry. and this long and inconclusive discussion from 2001 on the GCC mailing list)
一个丑陋的解决方法是自己设置功能,然后取消定义 __USE_SVID
:
#include <features.h>
#undef __USE_SVID
#include <random>
#include <iostream>
int main(){
std::cout << DOMAIN << std::endl;
return 0;
}
恕我直言,这应该没有必要。但就是这样。
math.h 中的宏 DOMAIN
与枚举和可能的其他类型发生冲突。我不知道该怎么做。
#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;
}
这是功能还是错误?
编辑* 脏修复:
#ifdef DOMAIN
#undef DOMAIN
#endif
§ 17.6.5.2 [res.on.headers] / N4140 的 1 说:
A C++ header may include other C++ headers. A C++ header shall provide the declarations and definitions that appear in its synopsis. A C++ header shown in its synopsis as including other C++ headers shall provide the declarations and definitions that appear in the synopses of those other headers.
因此,<algorithm>
到 #include <cmath>
是有效的,它会将有问题的宏常量注入到您的命名空间中。
但是请注意,标准 (§ 17.6.4.3.1 [macro.names] / 1) 不允许您的“快速修复”:
A translation unit that includes a standard library header shall not
#define
or#undef
names declared in any standard library header.
您必须为 enum
常量选择一个不同于 DOMAIN
的名称。
这是一个错误(或者 "wart" 如果你想大方一点)。
此答案的所有其余部分仅涉及 GCC 和 Gnu 标准 C 库头文件。 man
页面引用是 linux 系统(但我已将 link 添加到 man7.org)。
DOMAIN
宏来自 math.h
的 System V 支持。 (参见 man matherr
.) System V support is normally enabled by defining the _SVID_SOURCE
feature-test macro (see man feature_test_macros
),但如果定义了 _GNU_SOURCE
,它会与大量其他扩展一起启用,或者如果未定义功能测试宏,则默认情况下启用。
--std
选项或设置为 gnu##
,则 gcc
为 C 程序预定义 _GNU_SOURCE
。各种 --std=c##
选项导致 __STRICT_ANSI__
被定义。因此,使用某些明确的 C 标准编译 C 代码将抑制 System V 扩展。需要这样做是因为 System V 扩展不符合标准,甚至 Posix 也不兼容,因为它们污染了全局命名空间。 (DOMAIN
只是这种污染的一个例子。)
然而,即使指定了 --std=c++##
,g++
也会定义 _GNU_SOURCE
,因此系统 V 扩展将潜入。(感谢@dyp 提供 link对此 libstdc++ FAQ entry. and this long and inconclusive discussion from 2001 on the GCC mailing list)
一个丑陋的解决方法是自己设置功能,然后取消定义 __USE_SVID
:
#include <features.h>
#undef __USE_SVID
#include <random>
#include <iostream>
int main(){
std::cout << DOMAIN << std::endl;
return 0;
}
恕我直言,这应该没有必要。但就是这样。