首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >定义了"has_trivial_destructor“而不是"is_trivially_destructible”

定义了"has_trivial_destructor“而不是"is_trivially_destructible”
EN

Stack Overflow用户
提问于 2012-10-03 12:53:00
回答 3查看 3.5K关注 0票数 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,它有利于我使用的编译器:

代码语言:javascript
复制
#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

...but现在,我正在尝试与4.8用户和其他追逐该标准的编译器分享源代码。有没有更好的技巧来让这种情况的检测更“自动”,而不需要#define?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-10-04 04:56:43

这对我来说适用于GCC 4.7和4.8,正确地告诉我提供的是旧的还是新的特征:

代码语言:javascript
复制
#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

现在你可以定义你自己的可移植特征了:

代码语言:javascript
复制
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的语义与新特征不同,但对于不支持新特征的旧编译器来说,这是一个合理的近似值。

或者,您可以使用静态多态来根据可用的类型特征获得不同的代码,例如,通过专门化模板或通过重载和标记分派,如下所示:

代码语言:javascript
复制
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
  }

在此答案的制作过程中,没有宏受到损害。

票数 10
EN

Stack Overflow用户

发布于 2012-10-04 04:59:15

下面是一个非常老套的官方UB代码片段,它可以测试std名称空间是否使用has_trivial_destructor名称,是否具有trivially_destructible特征别名,并选择要检查的特征(如果has_trivial_destructor不可用,则为is_trivially_destructible)。

代码语言:javascript
复制
#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>>;

Live example.

票数 4
EN

Stack Overflow用户

发布于 2015-10-14 19:59:27

我也有类似的问题,之前我检查过GCC版本的宏(不幸的是,没有办法检查正确的libstd++版本,只有日期代码可用)。Previous Answer by Jonathan Wakely是一个很好的解决方案,但是使用libc++和其他库失败,这些库在版本化的内联名称空间中定义模板,或者通过使用将该名称空间映射到std。那样的话,原型就不合适了。

要使Jonathan Wakely中的代码适合,您需要检查libc++并定义正确的名称空间。

代码语言:javascript
复制
#include <type_traits>


#ifdef _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_NAMESPACE_STD
#else
namespace std {
#endif
  template<typename> struct has_trivial_destructor;
  template<typename> struct is_trivially_destructible;
// All unimplemented in gcc 4.9
  template<typename, typename...> struct is_trivially_constructible;
  template<typename> struct is_trivially_default_constructible;
  template<typename> struct is_trivially_copy_constructible;
  template<typename> struct is_trivially_move_constructible;
  template<typename> struct is_trivially_assignable;
  template<typename> struct is_trivially_copy_assignable;
  template<typename> struct is_trivially_move_assignable;
  template<typename> struct is_trivially_copyable;
#ifdef _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_END_NAMESPACE_STD
#else
} // namespace std
#endif

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" );
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12702103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档