我有一个Xcode项目,我正在迁移以与clang的选项-stdlib libc++
一起使用,以启用C ++ 11支持。我的一些源文件需要知道正在使用哪个库,例如我这样做:
#ifdef HAVE_CPP11_LIB_SUPPORT
#include <memory>
#else
#include <tr1/memory>
#endif
#ifdef HAVE_CPP11_LIB_SUPPORT
vector.emplace_back(newValue);
#else
vector.push_back(newValue);
#endif
虽然找到为此选项设置的预处理器宏(如果确实存在),但我遇到了麻烦。我试过将clang的输出转储为:
clang -x c++ -std=c++11 -stdlib=libc++ -dM -E - < /dev/null
与之比较:
clang -x c++ -std=c++11 -stdlib=libstdc++ -dM -E - < /dev/null
但是这给出了相同的结果。请注意,我不想打开我们是否使用c ++ 11 语言设置,但我们是否使用c ++ 11 库。在代码中有没有可靠的方法来检测这个?
答案 0 :(得分:7)
我不知道有任何可靠保证便携的方法,但这就是我现在使用的方法:
// libc++ detected: _LIBCPP_VERSION
// libstdc++ detected: __GLIBCXX__
#if defined(__clang__)
# if __has_include(<__config>) // defines _LIBCPP_VERSION
# include <__config>
# elif __has_include(<bits/c++config.h>) // defines __GLIBCXX__
# include <bits/c++config.h>
# else
# include <ios>
# endif
#elif defined(__GNUC__) // gcc does not have __has_include
# include <ios> // ios should include the c++config.h which defines __GLIBCXX__
#endif
这不好,但现在对我有用。
libc ++定义_LIBCPP_VERSION
并且stdc ++定义__GLIBCXX__
这很好,但不幸的是这些宏没有被编译器定义。相反,它们是在非标准头文件中定义的,除非包含该标题,否则无法测试它们的定义。
注意:显然stdc ++在旧版本中定义了__GLIBCPP__
。由于你需要c ++ 11,这不会成为一个问题。
Clang (编辑:标准,因为C ++ 17)有一个很好的功能__has_include
,可以用来测试这些,但如果没有找到任何标题,宏将回退到只包括一个标准的标题,希望在引擎盖下使用内部标题。我在这里<ios>
,但要包含的标准标题的选择取决于您。您可以查找包含内部标题的标题(类似于Linux上的gcc):
grep -Rl '#include <bits/c++config.h>' /usr/include/c++
选择您可能在项目中使用的任何标题。
由于这不能保证适用于任何给定的过去或未来的编译器/标准库版本,我不会依赖这些定义,除了可选功能,如:
#ifdef __GLIBCXX__
std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#endif
答案 1 :(得分:1)
#ifdef __has_include
# if __has_include(<ciso646>)
# include <ciso646>
# if defined(_LIBCPP_VERSION)
# define USING_LIBCPP 1
# endif
# endif
#endif
#if !USING_LIBCPP
# define USING_LIBSTDCXX 1
#endif
答案 2 :(得分:0)
如果您正在编写这些类型的检查,我建议您选择编译器/库版本并要求更新或更新版本。半使用C ++ 11库功能是没有意义的。在Mac OS X上,只需要使用clang++ -stdlib=libc++
编译。
答案 3 :(得分:0)
我使用下一个代码:
#include <cstddef> // for __GLIBCXX__
#ifdef __GLIBCXX__
# include <tr1/memory>
#else
# include <memory>
#endif