Ricerca…


Osservazioni

I tratti di tipo sono costrutti basati su modelli utilizzati per confrontare e testare le proprietà di diversi tipi in fase di compilazione. Possono essere utilizzati per fornire una logica condizionale in fase di compilazione che può limitare o estendere la funzionalità del codice in un modo specifico. La libreria dei caratteri di tipo è stata introdotta con lo standard c++11 che fornisce un numero di funzionalità diverse. È anche possibile creare modelli di confronto trait personalizzati.

Tratti di tipo standard

C ++ 11

L'intestazione type_traits contiene un insieme di classi template e helper per trasformare e controllare le proprietà dei tipi in fase di compilazione.

Questi tratti sono in genere utilizzati nei modelli per verificare gli errori degli utenti, supportare la programmazione generica e consentire ottimizzazioni.


La maggior parte dei caratteri tipografici viene utilizzata per verificare se un tipo soddisfa alcuni criteri. Questi hanno la seguente forma:

template <class T> struct is_foo;

Se la classe template è istanziata con un tipo che soddisfa alcuni criteri foo , allora is_foo<T> eredita da std::integral_constant<bool,true> (aka std::true_type ), altrimenti eredita da std::integral_constant<bool,false> (aka std::false_type ). Questo conferisce al tratto i seguenti membri:

costanti

static constexpr bool value

true se T soddisfa i criteri foo , false altrimenti

funzioni

operator bool

Restituisce value

C ++ 14

bool operator()

Restituisce value

tipi

Nome Definizione
value_type bool
type std::integral_constant<bool,value>

Il tratto può quindi essere utilizzato in costrutti come static_assert o std::enable_if . Un esempio con std::is_pointer :

template <typename T>
void i_require_a_pointer (T t) {
    static_assert(std::is_pointer<T>::value, "T must be a pointer type");
}

//Overload for when T is not a pointer type
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value>::type
does_something_special_with_pointer (T t) {
    //Do something boring
}

//Overload for when T is a pointer type
template <typename T>
typename std::enable_if<std::is_pointer<T>::value>::type 
does_something_special_with_pointer (T t) {
    //Do something special
}

Ci sono anche vari tratti che trasformano i tipi, come std::add_pointer e std::underlying_type . Questi tratti generalmente espongono un type membro di tipo singolo che contiene il tipo trasformato. Ad esempio, std::add_pointer<int>::type è int* .

Digitare le relazioni con std :: is_same

C ++ 11

La relazione di tipo std::is_same<T, T> viene utilizzata per confrontare due tipi. Valuterà come booleano, vero se i tipi sono uguali e falso se diversamente.

per esempio

// Prints true on most x86 and x86_64 compilers.
std::cout << std::is_same<int, int32_t>::value << "\n";
// Prints false on all compilers.
std::cout << std::is_same<float, int>::value << "\n";
// Prints false on all compilers.
std::cout  << std::is_same<unsigned int, int>::value << "\n";

Anche la relazione di tipo std::is_same funzionerà indipendentemente da typedef. Questo è effettivamente dimostrato nel primo esempio quando si confronta int == int32_t tuttavia questo non è completamente chiaro.

per esempio

// Prints true on all compilers.
typedef int MyType
std::cout << std::is_same<int, MyType>::value <<  "\n";

Usando std::is_same per avvisare quando si utilizza impropriamente una classe o una funzione std::is_same su modello.

Quando combinato con un std::is_same statico, il modello std::is_same può essere uno strumento prezioso per far rispettare l'uso corretto di classi e funzioni std::is_same su modelli.

Ad esempio una funzione che consente solo l'input da un int e una scelta di due strutture.

#include <type_traits>
struct foo {
  int member;
  // Other variables
};

struct bar {
  char member;
};

template<typename T>
int AddStructMember(T var1, int var2) {
  // If type T != foo || T != bar then show error message.
  static_assert(std::is_same<T, foo>::value || 
    std::is_same<T, bar>::value,
    "This function does not support the specified type.");
  return var1.member + var2;
}

Caratteri fondamentali del tipo

C ++ 11

Ci sono un certo numero di tratti di tipo diverso che confrontano tipi più generali.

È integrale:

Valuta come vero per tutti i tipi interi int , char , long , unsigned int ecc.

std::cout << std::is_integral<int>::value << "\n"; // Prints true.
std::cout << std::is_integral<char>::value << "\n"; // Prints true.
std::cout << std::is_integral<float>::value << "\n"; // Prints false.

È in virgola mobile:

Valuta come vero per tutti i tipi di virgola mobile. float , double , long double ecc.

std::cout << std::is_floating_point<float>::value << "\n"; // Prints true.
std::cout << std::is_floating_point<double>::value << "\n"; // Prints true.
std::cout << std::is_floating_point<char>::value << "\n"; // Prints false.

È Enum:

Valuta come vero per tutti i tipi enumerati, inclusa la enum class .

enum fruit {apple, pair, banana};
enum class vegetable {carrot, spinach, leek};
std::cout << std::is_enum<fruit>::value << "\n"; // Prints true.
std::cout << std::is_enum<vegetable>::value << "\n"; // Prints true.
std::cout << std::is_enum<int>::value << "\n"; // Prints false.

È puntatore:

Valuta come vero per tutti i puntatori.

std::cout << std::is_pointer<int *>::value << "\n"; // Prints true.
typedef int* MyPTR;
std::cout << std::is_pointer<MyPTR>::value << "\n"; // Prints true.
std::cout << std::is_pointer<int>::value << "\n"; // Prints false.

È classe:

Valuta come vero per tutte le classi e struct, ad eccezione della enum class .

struct FOO {int x, y;};
class BAR {
 public:
  int x, y;
};
enum class fruit {apple, pair, banana};
std::cout << std::is_class<FOO>::value << "\n"; // Prints true.
std::cout << std::is_class<BAR>::value << "\n"; // Prints true.
std::cout << std::is_class<fruit>::value << "\n"; // Prints false.
std::cout << std::is_class<int>::value << "\n"; // Prints false.

Tipo Proprietà

C ++ 11

Le proprietà del tipo confrontano i modificatori che possono essere posizionati su variabili diverse. L'utilità di questi tratti del genere non è sempre ovvia.

Nota: l'esempio seguente offre solo un miglioramento su un compilatore non ottimizzante. È una semplice dimostrazione di concetto, piuttosto che un esempio complesso.

es. Divisione veloce per quattro.

template<typename T>
inline T FastDivideByFour(cont T &var) {
  // Will give an error if the inputted type is not an unsigned integral type.    
  static_assert(std::is_unsigned<T>::value && std::is_integral<T>::value,
    "This function is only designed for unsigned integral types.");
  return (var >> 2);
}

È costante:

Questo valuterà come vero quando il tipo è costante.

std::cout << std::is_const<const int>::value << "\n"; // Prints true.
std::cout << std::is_const<int>::value << "\n"; // Prints false.

È volatile:

Questo verrà valutato come true quando il tipo è volatile.

std::cout << std::is_volatile<static volatile int>::value << "\n"; // Prints true.
std::cout << std::is_const<const int>::value << "\n"; // Prints false.

È firmato:

Questo valuterà come vero per tutti i tipi firmati.

std::cout << std::is_signed<int>::value << "\n"; // Prints true.
std::cout << std::is_signed<float>::value << "\n"; // Prints true.
std::cout << std::is_signed<unsigned int>::value << "\n"; // Prints false.
std::cout << std::is_signed<uint8_t>::value << "\n"; // Prints false.

Non firmato:

Valuterà come vero per tutti i tipi non firmati.

std::cout << std::is_unsigned<unsigned int>::value << "\n"; // Prints true.
std::cout << std::is_signed<uint8_t>::value << "\n"; // Prints true.
std::cout << std::is_unsigned<int>::value << "\n"; // Prints false.
std::cout << std::is_signed<float>::value << "\n"; // Prints false.


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow