C ++ how to handle tr1 and non-tr1 namespaces in portable code?

Is there a canonical way to solve namespace problems that arise when trying to save portable code between TR1 and not TR1 toolchain?

I have a VC ++ 2010 project that #include <type_traits> . I also have an LLVM 3.0 compiler that can handle this fine. This allows me to use patterns, for example:

 std::enable_if<typename> std::is_enum<typename> 

However, I also need to build and maintain this code in the Xang Xerode 4.5 compiler:

 $ /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 

This compiler does not have an include file, instead it has. However, this is causing me problems because the namespace has changed from std :: to __gnu_cxx ::, which means I have to use:

 __gnu_cxx::__enable_if<typename> 

Somehow I was able to determine that the definition of the __GLIBCXX__ symbol __GLIBCXX__ enough to determine whether I should use one or the other (not even sure if this is the right way to do this, but at the moment it works between compilers I use).

Therefore, I could resort to using preprocessor macros:

 #ifdef __GLIBCXX__ # include <tr1/type_traits> # define ENABLE_IF __gnu_cxx::__enable_if #else # include <type_traits> # define ENABLE_IF std::enable_if #endif 

But it looks like it might be a hack rather than the right solution. (Actually I tried this and it does not work, because trying to use __gnu_cxx::__enable_if causes this error:

 error: too few template arguments for class template '__enable_if' 
  • further digging suggests that this version of enable_if actually takes two template arguments. I am very lost now ...)

I thought of doing something like:

 #ifdef __GLIBCXX__ # include <tr1/type_traits> namespace __gnu_cxx = foo; #else # include <type_traits> namespace std = foo; #endif ... foo::enable_if< ... > 

However, this does not work because the template is called enable_if in one namespace, but __enable_if in another.

I am sure that I am not the first person to deal with this problem - can someone point me to industry best practices to resolve this issue? Or should I just use Boost?

There is a similar question (I think), but only a partial answer here . Are there any better options?

EDIT: I tried this using <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); 

However, this gives me the following compiler error in 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' 

So it looks like std :: enable_if and boost :: enable_if are not compatible.

+2
source share
1 answer

I will answer my question since I got something while working with boost::enable_if_c (note that replacing the replacement std::enable_if is equal to boost::enable_if_c , not boost::enable_if ).

 #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_enum.hpp> // this would work except one of my environments doesn't contain <complex> so it's // too inclusive. Better (for me) to use the more specific includes above. // #include <boost/type_traits.hpp> template <typename ValueType> class Extractor <ValueType, typename boost::enable_if_c<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 } }; 

However, I am still very interested to know if there is a better way to handle this than resorting to Boost.

+1
source

All Articles