std::common_type
Определён в заголовочном файле <type_traits> | ||
|---|---|---|
template< class... T > struct common_type; | (начиная с C++11) |
Определяет общий тип для всех типов T..., то есть тип, к которому можно явно преобразовать все T.... Если такой тип существует (согласно приведённым ниже правилам), член type задаёт этот тип. В противном случае член type отсутствует.
- Если
sizeof...(T)равно нулю, членtypeотсутствует. - Если
sizeof...(T)равно единице (то естьT...содержит только один типT0), членtypeзадаёт тот же тип, что и std::common_type<T0,T0>::type, если он существует; в противном случае членtypeотсутствует. - Если
sizeof...(T)равно двум (то естьT...содержит ровно два типаT1иT2), - Если применение
std::decayхотя бы к одному изT1иT2даёт другой тип, членtypeзадаёт тот же тип, что и std::common_type<std::decay<T1>::type,std::decay<T2>::type>::type, если он существует; если нет, членtypeотсутствует; - В противном случае, если для std::common_type<T1,T2> существует пользовательская специализация, используется эта специализация;
- В противном случае, если std::decay<decltype(false?std::declval<T1>():std::declval<T2>())>::type является допустимым типом, член
typeзадаёт этот тип; см. условный оператор;
| (начиная с C++20) |
- В противном случае член
typeотсутствует. - Если
sizeof...(T)больше двух (то естьT...состоит из типовT1, T2, R...), то, если существует std::common_type<T1,T2>::type, членtypeзадаёт std::common_type<typenamestd::common_type<T1,T2>::type,R...>::type, если такой тип существует. Во всех остальных случаях членtypeотсутствует.
Если какой-либо тип в пакете параметров T не является полным типом, типом void (возможно, с квалификаторами cv) или массивом неизвестной границы, поведение не определено.
Если инстанцирование шаблона, приведённого выше, прямо или косвенно зависит от неполного типа и при гипотетическом завершении этого типа результат инстанцирования мог бы измениться, поведение не определено.
Вложенные типы
| Имя | Определение |
|---|---|
type | общий тип для всех T |
Вспомогательные типы
template< class... T > using common_type_t = typename common_type<T...>::type; | (начиная с C++14) |
Специализации
Пользователи могут специализировать common_type для типов T1 и T2, если
- хотя бы один из
T1иT2зависит от пользовательского типа, и -
std::decayявляется тождественным преобразованием как дляT1, так и дляT2.
Если такая специализация содержит член с именем type, он должен быть открытым и однозначным членом, задающим тип без квалификаторов cv и без ссылки, к которому можно явно преобразовать как T1, так и T2. Кроме того, std::common_type<T1,T2>::type и std::common_type<T2,T1>::type должны задавать один и тот же тип.
Программа, добавляющая специализации common_type с нарушением этих правил, имеет неопределённое поведение.
Обратите внимание, что поведение программы, добавляющей специализацию любого другого шаблона из <type_traits>, не определено (за исключением std::basic_common_reference)(начиная с C++20).
Стандартная библиотека уже предоставляет следующие специализации:
|
(C++11) | специализирует признак std::common_type (специализация шаблона класса) |
|
(C++11) | специализирует признак std::common_type (специализация шаблона класса) |
|
(C++23) | определяет общий тип двух pair (специализация шаблона класса) |
|
(C++23) | определяет общий тип tuple и типа tuple-like (специализация шаблона класса) |
|
(C++23) | определяет общий тип итератора и адаптированного типа basic_const_iterator (специализация шаблона класса) |
Возможная реализация
// primary template (used for zero types)
template<class...>
struct common_type {};
// one type
template<class T>
struct common_type<T> : common_type<T, T> {};
namespace detail
{
template<class...>
using void_t = void;
template<class T1, class T2>
using conditional_result_t = decltype(false ? std::declval<T1>() : std::declval<T2>());
template<class, class, class = void>
struct decay_conditional_result {};
template<class T1, class T2>
struct decay_conditional_result<T1, T2, void_t<conditional_result_t<T1, T2>>>
: std::decay<conditional_result_t<T1, T2>> {};
template<class T1, class T2, class = void>
struct common_type_2_impl : decay_conditional_result<const T1&, const T2&> {};
// C++11 implementation:
// template<class, class, class = void>
// struct common_type_2_impl {};
template<class T1, class T2>
struct common_type_2_impl<T1, T2, void_t<conditional_result_t<T1, T2>>>
: decay_conditional_result<T1, T2> {};
}
// two types
template<class T1, class T2>
struct common_type<T1, T2>
: std::conditional<std::is_same<T1, typename std::decay<T1>::type>::value &&
std::is_same<T2, typename std::decay<T2>::type>::value,
detail::common_type_2_impl<T1, T2>,
common_type<typename std::decay<T1>::type,
typename std::decay<T2>::type>>::type {};
// 3+ types
namespace detail
{
template<class AlwaysVoid, class T1, class T2, class... R>
struct common_type_multi_impl {};
template<class T1, class T2, class...R>
struct common_type_multi_impl<void_t<typename common_type<T1, T2>::type>, T1, T2, R...>
: common_type<typename common_type<T1, T2>::type, R...> {};
}
template<class T1, class T2, class... R>
struct common_type<T1, T2, R...>
: detail::common_type_multi_impl<void, T1, T2, R...> {};
|
Примечания
Для арифметических типов, не подвергаемых повышению, общий тип можно рассматривать как тип арифметического выражения (возможно, смешанного режима), например T0() + T1() + ... + Tn().
Примеры
Демонстрирует арифметику смешанного режима для класса, определённого в программе:
#include <iostream>
#include <type_traits>
template<class T>
struct Number { T n; };
template<class T, class U>
constexpr Number<std::common_type_t<T, U>>
operator+(const Number<T>& lhs, const Number<U>& rhs)
{
return {lhs.n + rhs.n};
}
void describe(const char* expr, const Number<int>& x)
{
std::cout << expr << " is Number<int>{" << x.n << "}\n";
}
void describe(const char* expr, const Number<double>& x)
{
std::cout << expr << " is Number<double>{" << x.n << "}\n";
}
int main()
{
Number<int> i1 = {1}, i2 = {2};
Number<double> d1 = {2.3}, d2 = {3.5};
describe("i1 + i2", i1 + i2);
describe("i1 + d2", i1 + d2);
describe("d1 + i2", d1 + i2);
describe("d1 + d2", d1 + d2);
}
Вывод:
i1 + i2 is Number<int>{3}
i1 + d2 is Number<double>{4.5}
d1 + i2 is Number<double>{4.3}
d1 + d2 is Number<double>{5.8}
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| Отчёт об ошибке | Применён к | Опубликованное поведение | Правильное поведение |
|---|---|---|---|
| LWG 2141 | C++11 | тип результата условного оператора не приводился к типу после decay | тип результата приводится к типу после decay |
| LWG 2408 | C++11 |
common_type не поддерживал SFINAE | добавлена поддержка SFINAE |
| LWG 2460 | C++11 |
common_type было почти невозможно написать | уменьшено количество необходимых специализаций |
См. также
|
(C++20) | задаёт требование, что два типа имеют общий тип (концепт) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/types/common_type