Создание собственных признаков типов
Создавайте собственные признаки типов
«Создание собственных признаков типов» — бесплатный урок C++ Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Создание собственных признаков типов
Если в стандартной библиотеке нет нужного вам признака, его можно написать самостоятельно. Признак — это просто шаблон, предоставляющий ::value или ::type.
Первичный шаблон и специализация
Стандартный шаблон таков: первичный шаблон со значением по умолчанию false и специализация, соответствующая интересующему типу и устанавливающая значение true.
#include <iostream>
#include <type_traits>
template <typename T>
struct is_ptr : std::false_type {};
template <typename T>
struct is_ptr<T*> : std::true_type {};
int main() {
std::cout << is_ptr<int>::value << "\n";
std::cout << is_ptr<int*>::value << "\n";
return 0;
}Наследование от integral_constant
Унаследовав признак от std::true_type или std::false_type, вы автоматически получите член value, и признак будет вести себя как стандартные признаки типов.
Определение контейнера
Определить, похож ли тип на контейнер, можно по наличию вложенных членов. Здесь мы специализируем шаблон при наличии псевдонима типа value_type с помощью вспомогательного шаблона.
#include <iostream>
#include <vector>
#include <type_traits>
template <typename T, typename = void>
struct has_value_type : std::false_type {};
template <typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type {};
int main() {
std::cout << has_value_type<std::vector<int>>::value << "\n";
std::cout << has_value_type<int>::value << "\n";
return 0;
}Объяснение std::void_t
std::void_t<...> преобразует любой корректный список типов в void. Если какой-либо тип внутри списка некорректен, специализация отбрасывается с помощью SFINAE, поэтому используется первичный шаблон с false_type.
Определение функции-члена
Можно определить, есть ли у типа вызываемая функция-член size(), проверив это выражение в void_t.
#include <iostream>
#include <string>
#include <type_traits>
template <typename T, typename = void>
struct has_size : std::false_type {};
template <typename T>
struct has_size<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};
int main() {
std::cout << has_size<std::string>::value << "\n";
std::cout << has_size<int>::value << "\n";
return 0;
}declval
std::declval<T>() создаёт фиктивное значение типа T в невычисляемом контексте, позволяя записывать выражения decltype без создания объекта.
Преобразующий признак типа
Собственные признаки типов также могут создавать типы. Этот признак удаляет один уровень указателя.
#include <iostream>
#include <type_traits>
template <typename T>
struct remove_one_pointer { using type = T; };
template <typename T>
struct remove_one_pointer<T*> { using type = T; };
int main() {
using R = remove_one_pointer<int*>::type;
std::cout << std::is_same_v<R, int> << "\n";
return 0;
}Вспомогательные шаблоны _v и _t
Следуйте стилю стандартной библиотеки, добавляя шаблоны переменных и псевдонимов.
#include <iostream>
#include <type_traits>
template <typename T>
struct is_char : std::false_type {};
template <>
struct is_char<char> : std::true_type {};
template <typename T>
inline constexpr bool is_char_v = is_char<T>::value;
int main() {
std::cout << is_char_v<char> << "\n";
std::cout << is_char_v<int> << "\n";
return 0;
}Идиома обнаружения
Техника void_t обобщается в идиому обнаружения, которую формализует экспериментальный std::is_detected. Концепции C++20 делают значительную часть этой работы проще.
Проверка собственных признаков типов
Проверяйте собственные признаки типов с помощью static_assert, чтобы любая регрессия немедленно приводила к ошибке сборки.
#include <type_traits>
template <typename T>
struct is_void_like : std::false_type {};
template <>
struct is_void_like<void> : std::true_type {};
static_assert(is_void_like<void>::value);
static_assert(!is_void_like<int>::value);
int main() { return 0; }Быстрая проверка
Вспомните назначение std::void_t.
Итоги
Вы научились писать собственные признаки типов.
- Первичный шаблон по умолчанию даёт false, а специализация устанавливает true
- Наследуйтесь от
true_type/false_type void_tиdeclvalлежат в основе идиомы обнаружения- Добавляйте вспомогательные шаблоны
_v/_tи проверяйте их с помощьюstatic_assert
Часто задаваемые вопросы
Урок «Создание собственных признаков типов» бесплатный?
Да — полный текст урока «Создание собственных признаков типов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «Создание собственных признаков типов»?
Создавайте собственные признаки типов Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Создание собственных признаков типов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Исследование типов
- Преобразование типов
- Условная логика
- Создание собственных признаков типов