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

允我心安 提交于 2019-12-24 05:04:05

问题


Is there a canonical way to deal with the namespace issues that arise when trying to maintain portable code between a TR1 and non-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 templates such as:

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

However I also need to build and maintain this code on an Xcode 4.5 clang 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 doesn't seem to have a include file, instead it has a . However this is causing me problems because the namespace has changed from std:: to __gnu_cxx::, meaning I have to use:

__gnu_cxx::__enable_if<typename>

Somehow I was able to determine that the definition of the symbol __GLIBCXX__ is sufficient to determine whether I should use one or the other (not even sure that's the right way to do it, but for now it works between the compilers I'm using).

So 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 this seems like it might be more of a hack than a proper solution. (Actually I tried this and it doesn't 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'm now very lost...)

I thought about 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 doesn't work because the template is called enable_if in one namespace, but __enable_if in the other.

I'm sure I'm not the first person to deal with this problem - can someone point me at the industry best practice for resolving this please? Or should I just use Boost instead?

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

EDIT: I tried this, with <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 doesn't seem that std::enable_if and boost::enable_if are drop-in compatible.


回答1:


I'll answer my own question as I did get something working using boost::enable_if_c (note that the drop-in replacement for std::enable_if is 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'm still very curious to know whether there is a better way to deal with this than resorting to Boost.



来源:https://stackoverflow.com/questions/14823832/c-how-to-handle-tr1-and-non-tr1-namespaces-in-portable-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!