Buscar..


Observaciones

Los rasgos de tipo son construcciones con plantillas que se utilizan para comparar y probar las propiedades de diferentes tipos en el momento de la compilación. Se pueden usar para proporcionar una lógica condicional en el momento de la compilación que puede limitar o ampliar la funcionalidad de su código de una manera específica. La biblioteca de rasgos de tipo se incorporó con el estándar c++11 , que proporciona una serie de funcionalidades diferentes. También es posible crear sus propias plantillas de comparación de rasgos de tipo.

Rasgos de tipo estándar

C ++ 11

El encabezado type_traits contiene un conjunto de clases de plantilla y ayudantes para transformar y verificar las propiedades de los tipos en tiempo de compilación.

Estos rasgos se usan normalmente en las plantillas para verificar errores de los usuarios, admitir la programación genérica y permitir optimizaciones.


La mayoría de los rasgos de tipo se utilizan para verificar si un tipo cumple con algunos criterios. Estos tienen la siguiente forma:

template <class T> struct is_foo;

Si la clase de plantilla está instanciada con un tipo que cumple con algunos criterios foo , is_foo<T> hereda de std::integral_constant<bool,true> (también conocido como std::true_type ), de lo contrario, hereda de std::integral_constant<bool,false> (también conocido como std::false_type ). Esto le da al rasgo los siguientes miembros:

Constantes

static constexpr bool value

true si T cumple con los criterios foo , false contrario

Funciones

operator bool

Devuelve value

C ++ 14

bool operator()

Devuelve value

Los tipos

Nombre Definición
value_type bool
type std::integral_constant<bool,value>

El rasgo se puede usar en construcciones como static_assert o std::enable_if . Un ejemplo 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
}

También hay varios rasgos que transforman los tipos, como std::add_pointer y std::underlying_type . Estos rasgos generalmente exponen un type miembro de tipo único que contiene el tipo transformado. Por ejemplo, std::add_pointer<int>::type is int* .

Escribe relaciones con std :: is_same

C ++ 11

La relación de tipo std::is_same<T, T> se utiliza para comparar dos tipos. Se evaluará como booleano, verdadero si los tipos son los mismos y falso en caso contrario.

p.ej

// 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";

La relación de tipo std::is_same también funcionará independientemente de typedefs. Esto se demuestra realmente en el primer ejemplo cuando se compara int == int32_t sin embargo, esto no está del todo claro.

p.ej

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

Usar std::is_same para advertir cuando se usa incorrectamente una clase o función con plantilla.

Cuando se combina con una std::is_same estática, la plantilla std::is_same puede ser una herramienta valiosa para imponer el uso adecuado de las clases y funciones de plantilla.

por ejemplo, una función que solo permite la entrada desde un int y una opción de dos estructuras.

#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;
}

Rasgos fundamentales de tipo

C ++ 11

Hay una serie de rasgos de tipos diferentes que comparan tipos más generales.

Es integral:

Evalúa como verdadero para todos los tipos de enteros int , char , long , unsigned int etc.

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.

Es punto flotante:

Evalúa como verdadero para todos los tipos de punto flotante. float , double , long double etc.

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.

Es enum:

Evalúa como verdadero para todos los tipos enumerados, incluida 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.

Es puntero:

Evalúa como verdadero para todos los punteros.

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.

Es la clase:

Se evalúa como verdadero para todas las clases y estructuras, con la excepción de la 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 de propiedades

C ++ 11

Las propiedades de tipo comparan los modificadores que se pueden colocar sobre diferentes variables. La utilidad de estos rasgos de tipo no siempre es obvia.

Nota: El ejemplo a continuación solo ofrecería una mejora en un compilador que no optimiza. Es una simple prueba de concepto, en lugar de un ejemplo complejo.

Por ejemplo, dividir rápido por cuatro.

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);
}

Es constante:

Esto se evaluará como verdadero cuando el tipo es constante.

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

Es volátil:

Esto se evaluará como verdadero cuando el tipo es volátil.

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

Está firmado:

Esto se evaluará como verdadero para todos los tipos firmados.

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.

Está sin firmar:

Se evaluará como verdadero para todos los tipos sin firmar.

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow