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
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
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
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
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
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.