questo funziona per me con GCC 4.7 e 4.8, in modo corretto dicendomi che il vecchio o nuovo tratto è previsto:
#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. Dichiaro (ma non definisco) entrambi i tratti perché la libreria standard (probabilmente) non dichiarerà entrambi e se il nome non è dichiarato, non è possibile fare riferimento a std::is_trivially_destructible
. Quindi li dichiaro entrambi, ma solo quello definito dalla biblioteca sarà utilizzabile. L'aggiunta di dichiarazioni allo spazio dei nomi std
è tecnicamente indefinita, quindi usala a tuo rischio (non è probabile che cancelli il tuo disco rigido in questo caso però)
Sfortunatamente un compilatore più vecchio che non fornisce il nuovo tratto potrebbe non in grado di gestire il codice sia - non ho controllato se funziona con GCC 4.6
Ora è possibile definire il proprio tratto portatile:
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;
la semantica di has_trivial_destructor
non sono le stesse di il nuovo tratto, ma è un'approssimazione ragionevole per i compilatori più vecchi che non lo fanno il nuovo tratto.
In alternativa, è possibile utilizzare il polimorfismo statico per ottenere codice diverso a seconda del tipo di tratto disponibile, ad es. specializzandosi modelli o da sovraccarichi e tag di dispacciamento, in questo modo:
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
}
Non sono le macro sono stati lesi nella realizzazione di questa risposta.
L'utilizzo di una macro predefinita come "__GNUC_MINOR__" potrebbe renderlo un po 'più semplice. –
@VaughnCato Yup, è sicuramente un passo avanti, ma sembra che MSVC e altri stiano diventando conformi alle loro condizioni. Potrebbe consentire a un albero #if di evolvere per comprendere il set di utenti, ma sperava che fosse analogo a questo: http://stackoverflow.com/questions/257288/is-it-possible-to-write-ac-template-to -check-for-a-functions-esistenza – HostileFork