C++
Типовые черты
Поиск…
замечания
Типовыми признаками являются шаблонные конструкции, используемые для сравнения и тестирования свойств разных типов во время компиляции. Они могут использоваться для обеспечения условной логики во время компиляции, которая может ограничить или расширить функциональность вашего кода определенным образом. Библиотека признаков типов была введена с помощью стандарта c++11
который предоставляет несколько разных функций. Также возможно создать собственные шаблоны сравнения типов типов.
Стандартные типы
Заголовок type_traits
содержит набор классов шаблонов и помощников для преобразования и проверки свойств типов во время компиляции.
Эти черты обычно используются в шаблонах для проверки ошибок пользователя, поддержки общего программирования и обеспечения оптимизации.
Большинство типов признаков используются для проверки того, соответствует ли тип определенным критериям. Они имеют следующий вид:
template <class T> struct is_foo;
Если класс шаблона создается с типом, который удовлетворяет некоторым критериям foo
, то is_foo<T>
наследует от std::integral_constant<bool,true>
(aka std::true_type
), в противном случае он наследует от std::integral_constant<bool,false>
(aka std::false_type
). Это дает признак следующим членам:
Константы
static constexpr bool value
true
если T
удовлетворяет критериям foo
, false
противном случае
функции
operator bool
Возвращает value
bool operator()
Возвращает value
Типы
название | Определение |
---|---|
value_type | bool |
type | std::integral_constant<bool,value> |
Затем этот признак можно использовать в конструкциях, таких как static_assert
или std::enable_if
. Пример с 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
}
Существуют также различные черты, которые преобразуют типы, такие как std::add_pointer
и std::underlying_type
std::add_pointer
. Эти признаки обычно выставляют type
типа одного типа, который содержит преобразованный тип. Например, std::add_pointer<int>::type
is int*
.
Тип отношений с std :: is_same
Отношение std::is_same<T, T>
используется для сравнения двух типов. Он будет оцениваться как логический, true, если типы являются одинаковыми и ложными, если в противном случае.
например
// 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
также будет работать независимо от typedefs. Это фактически продемонстрировано в первом примере при сравнении int == int32_t
однако это не совсем ясно.
например
// Prints true on all compilers.
typedef int MyType
std::cout << std::is_same<int, MyType>::value << "\n";
Использование std::is_same
для предупреждения при неправильном использовании шаблонного класса или функции.
В сочетании со статическим утверждением шаблон std::is_same
может быть ценным инструментом для обеспечения правильного использования шаблонных классов и функций.
например, функция, которая допускает ввод только от int
и выбор двух структур.
#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;
}
Основные черты характера
Существует несколько различных типов признаков, которые сравнивают более общие типы.
Интеграл:
Оценивает как true для всех целых типов int
, char
, long
, 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.
Плавающая точка:
Вычисляет значение true для всех типов с плавающей запятой. float
, double
, long double
и т. д.
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.
Is Enum:
Вычисляет значение true для всех перечисленных типов, включая 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.
Является указателем:
Оценивает как истину для всех указателей.
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.
Класс:
Оценивает как true для всех классов и struct, за исключением 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.
Свойства типа
Свойства типа сравнивают модификаторы, которые могут быть помещены на разные переменные. Полезность этих черт типа не всегда очевидна.
Примечание. В приведенном ниже примере можно было бы предложить улучшения для не оптимизирующего компилятора. Это просто доказательство концепции, а не сложный пример.
например, Быстрое разделение на четыре.
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);
}
Постоянно:
Это будет считаться истинным, если тип является постоянным.
std::cout << std::is_const<const int>::value << "\n"; // Prints true.
std::cout << std::is_const<int>::value << "\n"; // Prints false.
Неустойчиво:
Это будет считаться истинным, когда тип изменчивый.
std::cout << std::is_volatile<static volatile int>::value << "\n"; // Prints true.
std::cout << std::is_const<const int>::value << "\n"; // Prints false.
Подписан:
Это будет считаться истинным для всех подписанных типов.
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.
Неподписано:
Будет оцениваться как истинное для всех неподписанных типов.
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.