2

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 は実際には 2 つのテンプレート引数を取ることが示唆されます。私は今とても迷っています...)

私は次のようなことを考えました:

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

... foo::enable_if< ... >

enable_ifただし、テンプレートは1 つの名前空間で呼び出されますが、別の名前空間で呼び出されるため、これは機能しません__enable_if

この問題に対処したのは私が初めてではないと確信しています。誰かがこれを解決するための業界のベストプラクティスを教えてもらえますか? または、代わりにブーストを使用する必要がありますか?

同様の質問があります(私は思います)が、ここでは部分的な回答のみです。より良いオプションはありますか?

編集:私はこれを試しました<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 はドロップイン互換ではないようです。

4

1 に答える 1

1

を使用して何かが機能するようになったので、自分の質問に答えますboost::enable_if_c( のドロップイン置換std::enable_ifboost::enable_if_cではなくであることに注意してください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
  }
};

ただし、ブーストに頼るよりもこれに対処するためのより良い方法があるかどうかを知りたいと思っています。

于 2013-02-12T01:47:40.600 に答える