6

C++11 標準の改良プロセス中に、is_trivially_destructibleはhas_trivial_destructorよりも優れた/より一貫性のある名前と見なされたようです。

私のg++ 4.7.1はまだ古い名前を使用しているため、これは比較的最近の開発であり、4.8の時点で標準に準拠するように修正されています。

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52702

私は、私が使用して#ifいるコンパイラを支持する を怠惰に使用してきました:

#if TRIVIAL_DESTRUCTOR_TYPE_TRAIT_MATCHES_STANDARD
template<class T>
using is_trivially_destructible = std::is_trivially_destructible<T>;
#else
template<class T>
using is_trivially_destructible = std::has_trivial_destructor<T>;
#endif

...しかし今、私はソースを 4.8 ユーザーや標準を追っている他のコンパイラと共有しようとしています。状況の検出をより「自動」にし、#define を必要としないためのより良いトリックはありますか?

4

3 に答える 3

10

これは、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
  }

この回答を作成する際にマクロに害はありませんでした。

于 2012-10-03T20:56:42.690 に答える
4

これは非常にハック的で公式なUBスニペットであり、std名前空間が名前を表しhas_trivial_destructortrivially_destructible特性エイリアスが正しい特性を取得してチェックするかどうかをテストできます(is_trivially_destructibleこの場合has_trivial_destructorは利用できません)。

#include <type_traits>

template<class>
struct has_trivial_destructor{ using test_fail = int; };

template<class>
struct is_trivially_destructible{ using test_fail = int; };

// very hackish and officially UB
namespace std{
  template<class T>
  struct inherit_htd : has_trivial_destructor<T>{};
  template<class T>
  struct inherit_itd : is_trivially_destructible<T>{};
}

namespace check_htd{
  template<class T>
  struct sfinae_false : ::std::false_type{};

  template<class T>
  auto test(int) -> sfinae_false<typename ::std::inherit_htd<T>::test_fail>;
  template<class>
  auto test(...) -> ::std::true_type;

  struct htd_available : decltype(test<int>(0)){};
}

template<class T>
using Apply = typename T::type;

template<class C, class T, class F>
using If = Apply<std::conditional<C::value,T,F>>;

template<class T>
using trivially_destructible = If<check_htd::htd_available, std::inherit_htd<T>, std::inherit_itd<T>>;

実例。

于 2012-10-03T20:59:15.330 に答える