“ has_trivial_destructor”;定义而不是“ is_trivially_destructible”。 [英] "has_trivial_destructor" defined instead of "is_trivially_destructible"

查看:190
本文介绍了“ has_trivial_destructor”;定义而不是“ is_trivially_destructible”。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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 
模板< T类>
使用is_trivially_destructible = std :: is_trivially_destructible< T;
#else
template< class T>使用is_trivially_destructible = std :: has_trivial_destructor< T>的
;
#endif

...但是现在我试图与4.8共享源用户和其他遵循该标准的编译器。有没有更好的技巧可以使情况检测更加自动并且不需要#define?

解决方案

这对我适用于GCC 4.7和4.8,正确地告诉我是否提供了旧特性或新特性:

  #include< type_traits> 

命名空间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>
静态std :: true_type test(int);

template< typename T2,bool = std :: has_trivial_destructor< T2> :: type :: value>
静态std :: false_type测试(...);

public:
typedef decltype(test< T>(0))类型;
};

template< typename T>
结构体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> 
使用is_trivially_destructible
=类型名称std :: conditional< have_cxx11_trait< T> :: value,
std :: is_trivially_destructible< T> ;,
std :: has_trivial_destructor< T ::类型;

has_trivial_destructor 的语义不是与新特性相同,但是对于不支持新特性的旧版编译器来说,这是一个合理的近似值。



或者,您可以使用静态多态性来获取不同的代码,具体取决于可用的类型特征,例如通过专门化模板或通过重载和标签分发,例如:

  template< typename T> 
void foo_helper(const T& ;, std :: true_type)
{
//使用std :: is_trivially_destructible
的代码}

template< typename &
void foo_helper(const T& ;, std :: false_type)
{
//使用std :: has_trivial_destructor
的不同代码}

template< typename &
void foo(const T& t)
{
//做普通的东西

//取决于特征的东西
foo_helper(t,has_cxx11_trait< ; T> {});

//更常见的东西
}

没有宏

During the refinement process of the C++11 standard, it seems that is_trivially_destructible was considered a better/more-consistent name than has_trivial_destructor.

This is a relatively recent development, as my g++ 4.7.1 still uses the old name, and it's been fixed to be compliant with the standard as of 4.8:

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

I've been lazily using an #if which favors the compiler I'm on:

#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 now I'm trying to share the source with 4.8 users and other compilers chasing the standard. Is there any better trick for making the detection of the situation more "automatic" and not require a #define?

解决方案

This works for me with GCC 4.7 and 4.8, correctly telling me whether the old or new trait is provided:

#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" );
}

N.B. I declare (but don't define) both traits because the standard library (probably) won't declare both and if the name isn't even declared then you can't refer to std::is_trivially_destructible. So I declare them both, but only the one defined by the library will be usable. Adding declarations to namespace std is technically undefined behaviour, so use it at your own risk (it's not likely to wipe your hard drive in this case though.)

Unfortunately an older compiler that doesn't provide the new trait might not be able to handle the code either -- I haven't checked if it works with GCC 4.6

Now you can define your own portable trait:

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;

The semantics of has_trivial_destructor aren't the same as the new trait, but it's a reasonable approximation for older compilers that don't support the new trait.

Alternatively, you could use static polymoprhism to get different code depending on which type trait is available, e.g. by specializing templates or by overloading and tag dispatching, like so:

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
  }

No macros were harmed in the making of this answer.

这篇关于“ has_trivial_destructor”;定义而不是“ is_trivially_destructible”。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆