﻿# std::common\_type

## Определение

_std::common\_type_ – это средство для вывода общего типа из стандартной библиотеки для произвольного числа переданных типов\. Впервые он появился в стандарте C\+\+11\. При выводе общего типа _std::common\_type_ полагается на тернарный оператор, делая некоторые преобразования, которые мы рассмотрим ниже\.

## Возможная реализация

```cpp
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_ и реализован в стандартной библиотеке\. Теперь, давайте подробно разберём, что тут происходит:

1. Объявляется основной вариативный шаблон класса\.
1. Для пустого списка шаблонных аргументов сделаем явную специализацию шаблона, которая ничего не содержит\.
1. Для одного шаблонного аргумента сделаем частичную специализацию, внутри которой будет лежать этот же тип после [_std::decay_](https://en.cppreference.com/w/cpp/types/decay), который уберёт CV\-квалификаторы, ссылки, добавит указатели функциям \(_function\-to\-pointer conversion_\) и преобразует массивы в указатели \(_array\-to\-pointer conversion_\)\.
1. Для двух шаблонных аргументов сделаем частичную специализацию, которая выведет результирующий тип на основе правила вывода общего типа тернарного оператора, применив перед этим _std::decay_ на переданные аргументы\.
1. Для трех и более шаблонных аргументов сделаем частичную специализацию, которая сначала посчитает общий тип для первых двух аргументов при помощи специализации для 2 аргументов\. Затем она рекурсивно инстанцирует себя, передав в качестве шаблонных аргументов общий тип для первой пары типов и оставшийся пакет шаблонных параметров\. По сути, _common\_type<a, b, c, d\>_ эквивалентно _common\_type<common\_type<common\_type<a, b\>, c\>, d\>_\. Пример на [C\+\+ Insights](https://cppinsights.io/lnk?code=I2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKdGVtcGxhdGUgPHR5cGVuYW1lIC4uLj4Kc3RydWN0IGNvbW1vbl90eXBlOyAvLyAoMSkKCnRlbXBsYXRlIDx0eXBlbmFtZSAuLi5Ucz4KdXNpbmcgY29tbW9uX3R5cGVfdCA9IHR5cGVuYW1lIGNvbW1vbl90eXBlPFRzLi4uPjo6dHlwZTsKCnRlbXBsYXRlIDw+CnN0cnVjdCBjb21tb25fdHlwZTw+IC8vICgyKQp7Cn07Cgp0ZW1wbGF0ZSA8Y2xhc3MgVD4Kc3RydWN0IGNvbW1vbl90eXBlPFQ+IC8vICgzKQp7CiAgdXNpbmcgdHlwZSA9IHN0ZDo6ZGVjYXlfdDxUPjsKfTsKCnRlbXBsYXRlIDxjbGFzcyBULCBjbGFzcyBVPgpzdHJ1Y3QgY29tbW9uX3R5cGU8VCwgVT4gICAgICAgICAvLyAoNCkKewogIHVzaW5nIHR5cGUgPSBzdGQ6OmRlY2F5X3Q8CiAgICAgIGRlY2x0eXBlKCB0cnVlID8gc3RkOjpkZWNsdmFsPCBzdGQ6OmRlY2F5X3Q8VD4gPigpCiAgICAgICAgICAgICAgICAgICAgIDogc3RkOjpkZWNsdmFsPCBzdGQ6OmRlY2F5X3Q8VT4gPigpICkgPjsKfTsKCnRlbXBsYXRlIDxjbGFzcyBULCBjbGFzcyBVLCBjbGFzcy4uLiBWPgpzdHJ1Y3QgY29tbW9uX3R5cGU8VCwgVSwgVi4uLj4gICAgICAgICAvLyAoNSkKewogIHVzaW5nIHR5cGUgPSB0eXBlbmFtZSBjb21tb25fdHlwZTx0eXBlbmFtZSBjb21tb25fdHlwZTxULFU+Ojp0eXBlLCBWLi4uPjo6dHlwZTsKfTsKCnRlbXBsYXRlCnN0cnVjdCBjb21tb25fdHlwZTxjaGFyLCBzaG9ydCwgaW50Pjs=&insightsOptions=cpp2a&std=cpp2a&rev=1.0)\.

## Дополнительные ссылки

1. [Описание поведения тернарного оператора](https://timsong-cpp.github.io/cppwp/n4868/expr.cond), драфт N4868 \(C\+\+20\)
1. [Описание поведения std::common\_type](https://timsong-cpp.github.io/cppwp/n4868/meta.trans.other), драфт N4868 \(C\+\+20\)