std:: common_type
|
Definiert im Header
<type_traits>
|
||
|
template
<
class
...
T
>
struct common_type ; |
(seit C++11) | |
Bestimmt den gemeinsamen Typ aller Typen
T...
, also einen Typ, in den alle
T...
explizit konvertiert werden können. Falls ein solcher Typ existiert (gemäß den nachfolgenden Regeln bestimmt), benennt das Mitglied
type
diesen Typ. Andernfalls existiert kein Mitglied
type
.
-
Wenn
sizeof...
(
T
)
null ist, existiert kein Member
type. -
Wenn
sizeof...
(
T
)
eins ist (d.h.
T...enthält nur einen TypT0), bezeichnet der Membertypedenselben Typ wie std :: common_type < T0, T0 > :: type falls dieser existiert; andernfalls existiert kein Membertype. -
Wenn
sizeof...
(
T
)
zwei ist (d.h.
T...enthält genau zwei TypenT1undT2),
-
-
Wenn die Anwendung von
std::decay
auf mindestens einen der Typen
T1undT2einen anderen Typ ergibt, bezeichnet das Mitgliedtypedenselben Typ wie std :: common_type < std:: decay < T1 > :: type , std:: decay < T2 > :: type > :: type , falls dieser existiert; falls nicht, gibt es kein Mitgliedtype; - Andernfalls, falls eine Benutzer-Spezialisierung für std :: common_type < T1, T2 > existiert, wird diese Spezialisierung verwendet;
-
Andernfalls, falls
std::
decay
<
decltype
(
false
?
std::
declval
<
T1
>
(
)
:
std::
declval
<
T2
>
(
)
)
>
::
type
ein gültiger Typ ist, bezeichnet das Mitglied
typediesen Typ, siehe den Bedingungsoperator ;
-
Wenn die Anwendung von
std::decay
auf mindestens einen der Typen
|
(seit C++20) |
-
-
Andernfalls gibt es kein Mitglied
type.
-
Andernfalls gibt es kein Mitglied
-
Wenn
sizeof...
(
T
)
größer als zwei ist (d.h.,
T...besteht aus den TypenT1, T2, R...), dann bezeichnet das Mitgliedtypestd :: common_type < typename std :: common_type < T1, T2 > :: type , R... > :: type , falls ein solcher Typ existiert. In allen anderen Fällen gibt es kein Mitgliedtype.
Wenn irgendein Typ in der Parameterpack
T
kein vollständiger Typ ist, (möglicherweise cv-qualifiziert)
void
, oder ein Array unbekannter Größe, ist das Verhalten undefiniert.
Wenn eine Instanziierung einer Vorlage oben direkt oder indirekt von einem unvollständigen Typ abhängt und diese Instanziierung ein anderes Ergebnis liefern könnte, wenn dieser Typ hypothetisch vervollständigt würde, ist das Verhalten undefiniert.
Inhaltsverzeichnis |
Verschachtelte Typen
| Name | Definition |
type
|
der gemeinsame Typ für alle
T
|
Hilfstypen
|
template
<
class
...
T
>
using common_type_t = typename common_type < T... > :: type ; |
(seit C++14) | |
Spezialisierungen
Benutzer können
common_type
für die Typen
T1
und
T2
spezialisieren, falls
-
Mindestens einer von
T1undT2hängt von einem benutzerdefinierten Typ ab, und -
std::decay
ist eine Identitätstransformation für sowohl
T1als auchT2.
Falls eine solche Spezialisierung ein Mitglied namens
type
besitzt, muss es sich um ein öffentliches und eindeutiges Mitglied handeln, das einen cv-unqualifizierten Nicht-Referenz-Typ benennt, in den sowohl
T1
als auch
T2
explizit konvertierbar sind. Zusätzlich müssen
std
::
common_type
<
T1, T2
>
::
type
und
std
::
common_type
<
T2, T1
>
::
type
denselben Typ bezeichnen.
Ein Programm, das
common_type
Spezialisierungen hinzufügt, die gegen diese Regeln verstoßen, hat undefiniertes Verhalten.
Beachten Sie, dass das Verhalten eines Programms, das eine Spezialisierung zu irgendeinem anderen Template
(außer
std::basic_common_reference
)
(seit C++20)
aus
<type_traits>
hinzufügt, undefiniert ist.
Die folgenden Spezialisierungen werden bereits von der Standardbibliothek bereitgestellt:
|
spezialisiert das
std::common_type
Merkmal
(Klassen-Template-Spezialisierung) |
|
|
spezialisiert das
std::common_type
Merkmal
(Klassen-Template-Spezialisierung) |
|
|
(C++23)
|
bestimmt den gemeinsamen Typ zweier
pair
s
(Klassen-Template-Spezialisierung) |
|
(C++23)
|
bestimmt den gemeinsamen Typ eines
tuple
und eines
tuple-like
Typs
(Klassen-Template-Spezialisierung) |
bestimmt den gemeinsamen Typ eines Iterators und eines angepassten
basic_const_iterator
Typs
(Klassen-Template-Spezialisierung) |
Mögliche Implementierung
// Primäres Template (verwendet für null Typen) template<class...> struct common_type {}; // Ein Typ 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 Implementierung: // 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> {}; } // Zwei Typen 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+ Typen 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...> {}; |
Hinweise
Für arithmetische Typen, die keiner Promotion unterliegen, kann der gemeinsame Typ als der Typ des (möglicherweise gemischten) arithmetischen Ausdrucks wie T0 ( ) + T1 ( ) + ... + Tn ( ) betrachtet werden.
Beispiele
Demonstriert gemischte Arithmetik mit einer programmdefinierten Klasse:
#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); }
Ausgabe:
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}
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| LWG 2141 | C++11 | der Ergebnistyp des bedingten Operators wurde nicht zerfallen | zerfiel den Ergebnistyp |
| LWG 2408 | C++11 |
common_type
war nicht SFINAE-freundlich
|
SFINAE-freundlich gemacht |
| LWG 2460 | C++11 |
common_type
Spezialisierungen waren nahezu unmöglich zu schreiben
|
reduzierte die Anzahl der
benötigten Spezialisierungen |
Siehe auch
|
(C++20)
|
spezifiziert, dass zwei Typen einen gemeinsamen Typ teilen
(Konzept) |