在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...but现在,我正在尝试与4.8用户和其他追逐该标准的编译器分享源代码。有没有更好的技巧来让这种情况的检测更“自动”,而不需要#define?
发布于 2012-10-04 04:56:43
这对我来说适用于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
}在此答案的制作过程中,没有宏受到损害。
发布于 2012-10-04 04:59:15
下面是一个非常老套的官方UB代码片段,它可以测试std名称空间是否使用has_trivial_destructor名称,是否具有trivially_destructible特征别名,并选择要检查的特征(如果has_trivial_destructor不可用,则为is_trivially_destructible)。
#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.
发布于 2015-10-14 19:59:27
我也有类似的问题,之前我检查过GCC版本的宏(不幸的是,没有办法检查正确的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" );
}https://stackoverflow.com/questions/12702103
复制相似问题