これは、GCC 4.7 および 4.8 で機能し、古いトレイトまたは新しいトレイトが提供されているかどうかを正しく示します。
#include <type_traits>
namespace std
{
template<typename> struct has_trivial_destructor;
template<typename> struct is_trivially_destructible;
}
template<typename T>
class have_cxx11_trait_helper
{
template<typename T2, bool = std::is_trivially_destructible<T2>::type::value>
static std::true_type test(int);
template<typename T2, bool = std::has_trivial_destructor<T2>::type::value>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
};
template<typename T>
struct have_cxx11_trait : have_cxx11_trait_helper<T>::type
{ };
int main()
{
static_assert( have_cxx11_trait<int>::value, "new trait" );
}
注意: 標準ライブラリは (おそらく) 両方を宣言しないため、両方の特性を宣言します (ただし、定義しません)。名前が宣言されていない場合は、 を参照できませんstd::is_trivially_destructible
。したがって、両方を宣言しますが、ライブラリで定義されたものだけが使用可能になります。名前空間に宣言を追加することstd
は、技術的に未定義の動作であるため、自己責任で使用してください (ただし、この場合、ハード ドライブが消去される可能性は低いです)。
残念ながら、新しいトレイトを提供しない古いコンパイラでも、コードを処理できない可能性があります。GCC 4.6 で動作するかどうかは確認していません。
これで、独自のポータブル トレイトを定義できます。
template<typename T>
using is_trivially_destructible
= typename std::conditional<have_cxx11_trait<T>::value,
std::is_trivially_destructible<T>,
std::has_trivial_destructor<T>>::type;
のセマンティクスはhas_trivial_destructor
新しいトレイトと同じではありませんが、新しいトレイトをサポートしていない古いコンパイラにとっては妥当な近似値です。
あるいは、次のように、テンプレートを特殊化するか、オーバーロードとタグのディスパッチを行うことにより、利用可能な型特性に応じて異なるコードを取得するために、静的多形性を使用することもできます。
template<typename T>
void foo_helper(const T&, std::true_type)
{
// code that uses std::is_trivially_destructible
}
template<typename T>
void foo_helper(const T&, std::false_type)
{
// different code using std::has_trivial_destructor
}
template<typename T>
void foo(const T& t)
{
// do common stuff
// stuff that depends on trait
foo_helper(t, has_cxx11_trait<T>{});
// more common stuff
}
この回答を作成する際にマクロに害はありませんでした。