std::common_type
Определение
std::common_type – это средство для вывода общего типа из стандартной библиотеки для произвольного числа переданных типов. Впервые он появился в стандарте C++11. При выводе общего типа std::common_type полагается на тернарный оператор, делая некоторые преобразования, которые мы рассмотрим ниже.
Возможная реализация
namespace std
{
template <typename ...>
struct common_type; // (1)
template <typename ...Ts>
using common_type_t = typename common_type<Ts...>::type;
template <>
struct common_type<> // (2)
{
};
template <class T>
struct common_type<T> // (3)
{
using type = std::decay_t<T>;
};
template <class T, class U>
struct common_type<T, U> // (4)
{
using type = decay_t<decltype( true ? declval< std::decay_t<T> >()
: declval< std::decay_t<U> >() ) >;
};
template <class T, class U, class ...V>
struct common_type<T, U, V...> // (5)
{
using type = typename common_type<typename common_type<T, U>::type,
V...>::type;
};
}
Стоит отметить, что примерно так common_type и реализован в стандартной библиотеке. Теперь, давайте подробно разберём, что тут происходит:
- Объявляется основной вариативный шаблон класса.
- Для пустого списка шаблонных аргументов сделаем явную специализацию шаблона, которая ничего не содержит.
- Для одного шаблонного аргумента сделаем частичную специализацию, внутри которой будет лежать этот же тип после std::decay, который уберёт CV-квалификаторы, ссылки, добавит указатели функциям (function-to-pointer conversion) и преобразует массивы в указатели (array-to-pointer conversion).
- Для двух шаблонных аргументов сделаем частичную специализацию, которая выведет результирующий тип на основе правила вывода общего типа тернарного оператора, применив перед этим std::decay на переданные аргументы.
- Для трех и более шаблонных аргументов сделаем частичную специализацию, которая сначала посчитает общий тип для первых двух аргументов при помощи специализации для 2 аргументов. Затем она рекурсивно инстанцирует себя, передав в качестве шаблонных аргументов общий тип для первой пары типов и оставшийся пакет шаблонных параметров. По сути, common_type<a, b, c, d> эквивалентно common_type<common_type<common_type<a, b>, c>, d>. Пример на C++ Insights.
Дополнительные ссылки
- Описание поведения тернарного оператора, драфт N4868 (C++20)
- Описание поведения std::common_type, драфт N4868 (C++20)
0