& Quot; has_trivial_destructor & Quot; определено вместо & quot; is_trivially_destructible & quot;

В процессе уточнения стандарта 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?

6

Решение

Это работает для меня с 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
}

При создании этого ответа не пострадали макросы.

10

Другие решения

Вот очень Hackish и официально UB фрагмент, который может проверить, является ли std пространство имен has_trivial_destructor имя и имеет trivially_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>>;

Живой пример.

4

У меня есть похожие проблемы, и ранее я проверял макросы версии GCC (к сожалению, нет способа проверить правильность версии libstd ++, доступен только код даты).
Предыдущий ответ Джонатана Уэйкли является хорошим решением, но не работает с libc ++ и, возможно, с другими библиотеками, которые определяют шаблоны в версионном встроенном пространстве имен или отображают это пространство имен в std с помощью. Таким образом, прототипы не подходят.

Чтобы сделать код из Jonathan Wakely подходящим, вам нужно проверить libc ++ и определить правильное пространство имен.

#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