在尝试维护 TR1 和非 TR1 工具链之间的可移植代码时,是否有一种规范的方法来处理出现的命名空间问题?
我有一个 VC++2010 项目#include <type_traits>
。我还有一个 LLVM 3.0 编译器可以很好地处理这个问题。这允许我使用模板,例如:
std::enable_if<typename>
std::is_enum<typename>
但是,我还需要在 Xcode 4.5 clang 编译器上构建和维护此代码:
$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang --version
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.4.2
Thread model: posix
这个编译器似乎没有包含文件,而是有一个 . 然而,这给我带来了问题,因为命名空间已从 std:: 更改为 __gnu_cxx::,这意味着我必须使用:
__gnu_cxx::__enable_if<typename>
不知何故,我能够确定符号的定义__GLIBCXX__
足以确定我应该使用一个还是另一个(甚至不确定这是正确的方法,但现在它在我正在使用的编译器之间工作)。
所以我可以求助于使用预处理器宏:
#ifdef __GLIBCXX__
# include <tr1/type_traits>
# define ENABLE_IF __gnu_cxx::__enable_if
#else
# include <type_traits>
# define ENABLE_IF std::enable_if
#endif
但这似乎更像是一种黑客攻击,而不是一个适当的解决方案。(其实我试过这个还是不行,因为尝试使用__gnu_cxx::__enable_if
会导致这个错误:
error: too few template arguments for class template '__enable_if'
- 进一步挖掘表明,这个版本的 enable_if 实际上采用了两个模板参数。我现在很迷茫......)
我想过做类似的事情:
#ifdef __GLIBCXX__
# include <tr1/type_traits>
namespace __gnu_cxx = foo;
#else
# include <type_traits>
namespace std = foo;
#endif
... foo::enable_if< ... >
但是,这不起作用,因为模板enable_if
在一个命名空间中调用,但__enable_if
在另一个命名空间中调用。
我确定我不是第一个处理这个问题的人 - 有人可以指出解决这个问题的行业最佳实践吗?还是我应该只使用 Boost 代替?
有一个类似的问题(我认为),但这里只有部分答案。有更好的选择吗?
编辑:我试过这个,用<boost/type_traits.hpp>
:
#include <boost/type_traits.hpp>
template <typename ValueType>
class Extractor <ValueType, typename boost::enable_if<boost::is_enum<ValueType>::value>::type> {
public:
ValueType extract(double value) {
return static_cast<ValueType>(static_cast<int>(value)); // cast to int first, then enum, to satisfy VC++2010
}
};
enum MyEnum { Enum0, Enum1 };
Extractor<MyEnum> e;
MyEnum ev = e.extract(1.0);
但是,这给了我 Xcode 4.5 中的以下编译器错误:
error: expected a qualified name after 'typename'
class Extractor <ValueType, typename boost::enable_if<boost::is_enum<ValueType>::value>::type> {
^
error: unknown type name 'type'
因此,std::enable_if 和 boost::enable_if 似乎不兼容。