Szukaj…


Uwagi

Cechy typu to konstrukcje szablonowe używane do porównywania i testowania właściwości różnych typów w czasie kompilacji. Można ich użyć do zapewnienia logiki warunkowej w czasie kompilacji, która może ograniczyć lub rozszerzyć funkcjonalność kodu w określony sposób. Biblioteka cech typu została wprowadzona ze standardem c++11 który zapewnia szereg różnych funkcjonalności. Możliwe jest również tworzenie własnych szablonów porównania cech typu.

Standardowe cechy typu

C ++ 11

Nagłówek type_traits zawiera zestaw klas szablonów i pomocników do przekształcania i sprawdzania właściwości typów w czasie kompilacji.

Te cechy są zwykle używane w szablonach do sprawdzania błędów użytkownika, obsługi programowania ogólnego i umożliwienia optymalizacji.


Większość cech typu służy do sprawdzania, czy typ spełnia określone kryteria. Mają one następującą formę:

template <class T> struct is_foo;

Jeśli instancja klasy szablonu jest tworzona z typem spełniającym niektóre kryteria foo , to is_foo<T> dziedziczy po std::integral_constant<bool,true> (aka std::true_type ), w przeciwnym razie dziedziczy po std::integral_constant<bool,false> (aka std::false_type ). Daje to cechę następującym członkom:

Stałe

static constexpr bool value

true jeśli T spełnia kryteria foo , false przeciwnym razie

Funkcje

operator bool

Zwraca value

C ++ 14

bool operator()

Zwraca value

Rodzaje

Nazwa Definicja
value_type bool
type std::integral_constant<bool,value>

Tę cechę można następnie zastosować w konstrukcjach takich jak static_assert lub std::enable_if . Przykład z 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
}

Istnieją również różne cechy, które przekształcają typy, takie jak std::add_pointer i std::underlying_type std::add_pointer . Te cechy ogólnie ujawniają type elementu typu jeden typ, który zawiera typ przekształcony. Na przykład std::add_pointer<int>::type is int* .

Wpisz relacje z std :: is_same

C ++ 11

std::is_same<T, T> służy do porównania dwóch typów. Zostanie oceniony jako logiczny, prawda, jeśli typy są takie same, a fałsz, jeśli inaczej.

na przykład

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

std::is_same typu std::is_same będzie również działać niezależnie od typedefs. Jest to faktycznie pokazane w pierwszym przykładzie przy porównywaniu int == int32_t jednak nie jest to całkowicie jasne.

na przykład

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

Użycie std::is_same do ostrzeżenia, gdy niepoprawnie używa się szablonowej klasy lub funkcji.

W połączeniu ze statycznym potwierdzeniem szablon std::is_same może być cennym narzędziem w wymuszaniu prawidłowego użycia klas i funkcji szablonowych.

np. funkcja, która pozwala tylko na wejście z int i wybór dwóch struktur.

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

Podstawowe cechy typu

C ++ 11

Istnieje wiele różnych cech typów, które porównują bardziej ogólne typy.

Jest zintegrowany:

Ocenia się jako prawda dla wszystkich typów liczb całkowitych int , char , long , unsigned int itp.

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.

Jest zmiennoprzecinkowy:

Ocenia się jako prawdziwe dla wszystkich typów zmiennoprzecinkowych. float , double , long double itp.

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.

Czy Enum:

Ocenia się jako prawdziwe dla wszystkich typów wyliczanych, w tym 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.

Czy wskaźnik:

Ocenia się jako prawdziwe dla wszystkich wskaźników.

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.

Czy klasa:

Ocenia się jako prawdziwe dla wszystkich klas i struktur, z wyjątkiem 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.

Wpisz właściwości

C ++ 11

Właściwości typu porównują modyfikatory, które można umieścić na różnych zmiennych. Przydatność tego typu cech nie zawsze jest oczywista.

Uwaga: Poniższy przykład oferuje tylko ulepszenie nieoptymalizującego kompilatora. Jest to prosty dowód koncepcji, a nie złożony przykład.

np. Szybki podział przez cztery.

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

Czy jest stały:

Będzie to oceniane jako prawda, gdy typ jest stały.

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

Jest lotny:

Zostanie to ocenione jako prawdziwe, gdy typ jest niestabilny.

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

Jest podpisany:

Będzie to oceniane jako prawdziwe dla wszystkich podpisanych typów.

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.

Jest niepodpisany:

Będzie oceniane jako prawdziwe dla wszystkich typów niepodpisanych.

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow