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<typename std::common_type<T1, T2>::type, R...>::type, если такой тип существует. Во всех остальных случаях членаtypeнет.
Типы в параметре-упаковке T должны быть полными типами, (возможно, с квалификаторами cv) void или массивами неизвестной длины. В противном случае, поведение не определено.
Если экземпляр шаблона выше зависит, напрямую или косвенно, от неполного типа, и этот экземпляр мог бы дать другой результат, если бы этот тип был гипотетически завершён, поведение не определено.
Члены-типы
| Название | Определение |
|---|---|
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 специализации в нарушение этих правил, имеет неопределённое поведение.
Обратите внимание, что поведение программы, которая добавляет специализацию к любому другому шаблону (кроме std::basic_common_reference)(с C++20) из <type_traits> не определено.
Следующие специализации уже предоставляются стандартной библиотекой:
|
(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++.
| DR | Применён к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| LWG 2141 | C++11 |
common_type<int, int>::type это int&& | тип результата с применением 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/w/cpp/types/common_type