在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?
答案 0 :(得分: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" );
}
N.B。我声明(但没有定义)这两个特征,因为标准库(可能)不会声明两者,如果名称甚至没有声明,那么你就不能引用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
}
在回答这个问题时,没有任何宏受到伤害。
答案 1 :(得分:4)
这是一个非常 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>>;
答案 2 :(得分:2)
我有类似的问题,之前已经检查过GCC Version Macros(遗憾的是没有办法检查正确的libstd ++版本,只提供日期代码)。 Previous Answer by Jonathan Wakely是一个很好的解决方案,但是使用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" );
}