Свойства типов (type traits) и преобразования типов (type transformations) — это инструменты, предоставляемые в стандартной библиотеке C++ (в заголовке <type_traits>), которые позволяют получать информацию о типах и выполнять преобразования типов на этапе компиляции.

  • Свойства типов: Позволяют проверять характеристики типов (например, является ли тип числовым, указателем и т.д.).
  • Преобразования типов: Позволяют изменять типы, например, удалять константность, добавлять ссылки и т.д.

Примеры свойств типов

Пример 1: Проверка свойств типов

#include <iostream>
#include <type_traits>
 
int main() {
    std::cout << std::boolalpha;
 
    std::cout << "is_integral<int>::value: " << std::is_integral<int>::value << std::endl; // true
    std::cout << "is_integral<float>::value: " << std::is_integral<float>::value << std::endl; // false
 
    std::cout << "is_pointer<int*>::value: " << std::is_pointer<int*>::value << std::endl; // true
    std::cout << "is_pointer<int>::value: " << std::is_pointer<int>::value << std::endl; // false
 
    return 0;
}

Пример 2: Условное включение кода на основе свойств типов

#include <iostream>
#include <type_traits>
 
// Функция работает только с указателями
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, void>::type
process(T t) {
    std::cout << "Processing pointer" << std::endl;
}
 
// Перегрузка для не указателей
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, void>::type
process(T t) {
    std::cout << "Processing non-pointer" << std::endl;
}
 
int main() {
    int x = 42;
    int* p = &x;
 
    process(x); // Processing non-pointer
    process(p); // Processing pointer
 
    return 0;
}

Примеры преобразований типов

Пример 1: Преобразование типов с удалением константности

#include <iostream>
#include <type_traits>
 
int main() {
    using ConstInt = const int;
    using NonConstInt = std::remove_const<ConstInt>::type;
 
    std::cout << "std::is_const<ConstInt>::value: " << std::is_const<ConstInt>::value << std::endl; // true
    std::cout << "std::is_const<NonConstInt>::value: " << std::is_const<NonConstInt>::value << std::endl; // false
 
    return 0;
}

Пример 2: Добавление ссылки к типу

#include <iostream>
#include <type_traits>
 
int main() {
    using Int = int;
    using IntRef = std::add_lvalue_reference<Int>::type;
 
    std::cout << "std::is_reference<Int>::value: " << std::is_reference<Int>::value << std::endl; // false
    std::cout << "std::is_reference<IntRef>::value: " << std::is_reference<IntRef>::value << std::endl; // true
 
    return 0;
}

Продвинутые примеры

Пример: Проверка нескольких условий с помощью SFINAE

#include <iostream>
#include <type_traits>
 
// Функция работает только с указателями на числовые типы
template <typename T>
typename std::enable_if<std::is_pointer<T>::value && std::is_arithmetic<typename std::remove_pointer<T>::type>::value, void>::type
process(T t) {
    std::cout << "Processing pointer to arithmetic type" << std::endl;
}
 
int main() {
    int x = 42;
    int* p = &x;
    float* f = nullptr;
    std::string s = "Hello";
 
    process(p); // Processing pointer to arithmetic type
    process(f); // Processing pointer to arithmetic type
    // process(s); // Error: No matching function for call to 'process'
 
    return 0;
}

Пример: Преобразование типов для удаления ссылок и константности

#include <iostream>
#include <type_traits>
 
template <typename T>
void printTypeInfo() {
    using NonConstType = typename std::remove_const<T>::type;
    using NonRefType = typename std::remove_reference<NonConstType>::type;
 
    std::cout << "Is const: " << std::is_const<T>::value << std::endl;
    std::cout << "Is reference: " << std::is_reference<T>::value << std::endl;
    std::cout << "Base type: " << typeid(NonRefType).name() << std::endl;
}
 
int main() {
    printTypeInfo<const int&>(); // Is const: true, Is reference: true, Base type: int
    printTypeInfo<int>();        // Is const: false, Is reference: false, Base type: int
 
    return 0;
}