编写代码,当“has_trivial_destructor”而不是“is_trivially_destructible”。 [英] Writing code that works when "has_trivial_destructor" is defined, instead of "is_trivially_destructible"

查看:916
本文介绍了编写代码,当“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 
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用户和其他编译器追逐标准。

解决方案

/ div>

这适用于我与GCC 4.7和4.8,正确地告诉我是否提供旧的或新的trait:

  #include< type_traits> 

namespace std
{
template< typename> struct has_trivial_destructor;
template< typename> struct is_trivially_destructible;
}

template< typename T>
class has_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。我声明(但不定义)两个traits,因为标准库(可能)不会声明两者,如果名称甚至没有声明,那么你不能引用 std :: is_trivially_destructible 。所以我声明它们,但只有由库定义的一个将可用。添加声明到命名空间 std 是技术上未定义的行为,所以使用它自己的风险(在这种情况下不可能擦拭你的硬盘驱动器。)

$不幸的是,不提供新trait的旧编译器可能无法处理代码 - 我没有检查它是否与GCC 4.6一起使用



现在您可以定义自己的便携式特性:

  template< typename T& 
使用is_trivially_destructible
= typename std :: conditional< have_cxx11_trait< T> :: value,
std :: is_trivially_destructible< T>,
std :: has_trivial_destructor< T> ::类型;

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



或者,您可以使用static polymoprhism来获取不同的代码,具体取决于可用的类型特征。通过专门化模板或通过重载和标签分派,如下:

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

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

template< typename T>
void foo(const T& t)
{
//做常用的东西

//取决于trait的东西
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天全站免登陆