Suche…


Bemerkungen

Typmerkmale sind Templatkonstrukte, mit denen die Eigenschaften verschiedener Typen zur Kompilierzeit verglichen und getestet werden. Sie können verwendet werden, um eine bedingte Logik zur Kompilierzeit bereitzustellen, die die Funktionalität Ihres Codes auf bestimmte Weise einschränken oder erweitern kann. Die Typmerkmalsbibliothek wurde mit dem Standard c++11 der eine Reihe verschiedener Funktionalitäten bietet. Es ist auch möglich, eigene Vorlagen für den Vergleich von Typenmerkmalen zu erstellen.

Standardmerkmale

C ++ 11

Der type_traits Header enthält eine Reihe von Vorlagenklassen und Helfern, mit denen die Eigenschaften von Typen type_traits der Kompilierung transformiert und überprüft werden können.

Diese Merkmale werden normalerweise in Vorlagen verwendet, um auf Benutzerfehler zu prüfen, generische Programmierung zu unterstützen und Optimierungen zu ermöglichen.


Die meisten Typmerkmale werden verwendet, um zu überprüfen, ob ein Typ einige Kriterien erfüllt. Diese haben folgende Form:

template <class T> struct is_foo;

Wenn die Vorlagenklasse mit einem Typ instanziiert wird, der einige Kriterien foo erfüllt, erbt is_foo<T> von std::integral_constant<bool,true> (aka std::true_type ), andernfalls erbt sie von std::integral_constant<bool,false> (auch bekannt als std::false_type ). Dies gibt dem Merkmal die folgenden Mitglieder:

Konstanten

static constexpr bool value

true wenn T die Kriterien foo erfüllt, andernfalls false

Funktionen

operator bool

Gibt den value

C ++ 14

bool operator()

Gibt den value

Typen

Name Definition
value_type bool
type std::integral_constant<bool,value>

Das Merkmal kann dann in Konstrukten wie static_assert oder std::enable_if . Ein Beispiel mit 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
}

Es gibt auch verschiedene Merkmale, die Typen transformieren, z. B. std::add_pointer und std::underlying_type . Diese Merkmale stellen im Allgemeinen einen einzelnen type bereit, der den transformierten Typ enthält. Beispiel: std::add_pointer<int>::type ist int* .

Geben Sie Relations mit std :: is_same ein

C ++ 11

Die Beziehung std::is_same<T, T> wird zum Vergleich zweier Typen verwendet. Es wird als boolean ausgewertet, true, wenn die Typen gleich sind, andernfalls false.

z.B

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

Die std::is_same funktioniert auch unabhängig von Typedefs. Dies wird im ersten Beispiel beim Vergleich von int == int32_t demonstriert. Dies ist jedoch nicht ganz klar.

z.B

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

Verwenden von std::is_same zum std::is_same , wenn eine Klasse oder Funktion mit Vorlagen nicht ordnungsgemäß verwendet wird.

In Kombination mit einer statischen std::is_same kann die Vorlage std::is_same ein wertvolles Werkzeug sein, um die ordnungsgemäße Verwendung von Klassen und Funktionen mit Vorlagen zu erzwingen.

ZB eine Funktion, die nur Eingaben von einem int und die Wahl von zwei Strukturen erlaubt.

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

Grundtypeigenschaften

C ++ 11

Es gibt eine Reihe verschiedener Typmerkmale, die allgemeinere Typen vergleichen.

Ist Integral:

Wird für alle Integer-Typen int , char , long , unsigned int usw. als wahr unsigned int .

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.

Ist Floating Point:

Wird für alle Gleitkommatypen als wahr ausgewertet. float , double , long double usw.

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.

Ist Enum:

Wird für alle Aufzählungstypen, einschließlich der Aufzählungsklasse, als wahr 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.

Ist Zeiger:

Bewertet für alle Zeiger als wahr.

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.

Ist Klasse:

Wird für alle Klassen und struct mit Ausnahme von enum class als wahr 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.

Geben Sie Eigenschaften ein

C ++ 11

Typeneigenschaften vergleichen die Modifizierer, die für verschiedene Variablen platziert werden können. Die Nützlichkeit dieser Merkmale ist nicht immer offensichtlich.

Hinweis: Das folgende Beispiel bietet nur eine Verbesserung eines nicht optimierenden Compilers. Es ist eher ein Beweis für das Konzept als ein komplexes Beispiel.

zB schnelle Division durch vier.

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

Ist konstant:

Dies wird als wahr ausgewertet, wenn type konstant ist.

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

Ist flüchtig:

Dies wird als wahr ausgewertet, wenn der Typ flüchtig ist.

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

Ist unterschrieben:

Dies wird für alle signierten Typen als wahr bewertet.

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.

Ist unsigniert:

Wird für alle vorzeichenlosen Typen als wahr ausgewertet.

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow