Namespaces
Variants

std:: common_type

From cppreference.net
Metaprogramming library
Type traits
Type categories
(C++11)
(C++11) ( DR* )
Type properties
(C++11)
(C++11)
(C++14)
(C++11) (deprecated in C++26)
(C++11) ( until C++20* )
(C++11) (deprecated in C++20)
(C++11)
Type trait constants
Metafunctions
(C++17)
Supported operations
Relationships and property queries
Type modifications
Type transformations
(C++11) (deprecated in C++23)
(C++11) (deprecated in C++23)
(C++11)
(C++11) ( until C++20* ) (C++17)

common_type
(C++11)
(C++11)
(C++17)
Compile-time rational arithmetic
Compile-time integer sequences
Défini dans l'en-tête <type_traits>
template < class ... T >
struct common_type ;
(depuis C++11)

Détermine le type commun parmi tous les types T... , c'est-à-dire un type vers lequel tous les T... peuvent être explicitement convertis. Si un tel type existe (tel que déterminé selon les règles ci-dessous), le membre type nomme ce type. Sinon, il n'y a pas de membre type .

  • Si sizeof... ( T ) est zéro, il n'y a pas de membre type .
  • Si sizeof... ( T ) est un (c'est-à-dire, T... contient seulement un type T0 ), le membre type désigne le même type que std :: common_type < T0, T0 > :: type s'il existe ; sinon il n'y a pas de membre type .
  • Si sizeof... ( T ) est deux (c'est-à-dire, T... contient exactement deux types T1 et T2 ),
  • Si l'application de std::decay à au moins l'un des types T1 et T2 produit un type différent, le membre type désigne le même type que std :: common_type < std:: decay < T1 > :: type , std:: decay < T2 > :: type > :: type , s'il existe ; sinon, il n'y a pas de membre type ;
  • Sinon, s'il existe une spécialisation utilisateur pour std :: common_type < T1, T2 > , cette spécialisation est utilisée ;
  • Sinon, si std:: decay < decltype ( false ? std:: declval < T1 > ( ) : std:: declval < T2 > ( ) ) > :: type est un type valide, le membre type désigne ce type, voir l'opérateur conditionnel ;
(depuis C++20)
  • Sinon, il n'y a aucun membre type .
  • Si sizeof... ( T ) est supérieur à deux (c'est-à-dire, T... consiste en les types T1, T2, R... ), alors si std :: common_type < T1, T2 > :: type existe, le membre type dénote std :: common_type < typename std :: common_type < T1, T2 > :: type , R... > :: type si un tel type existe. Dans tous les autres cas, il n'y a pas de membre type .

Si un type quelconque dans le pack de paramètres T n'est pas un type complet, (éventuellement qualifié cv) void , ou un tableau de limite inconnue, le comportement est indéfini.

Si l'instanciation d'un template ci-dessus dépend, directement ou indirectement, d'un type incomplet, et que cette instanciation pourrait produire un résultat différent si ce type était hypothétiquement complété, le comportement est indéfini.

Table des matières

Types imbriqués

Nom Définition
type le type commun pour tous les T

Types auxiliaires

template < class ... T >
using common_type_t = typename common_type < T... > :: type ;
(depuis C++14)

Spécialisations

Les utilisateurs peuvent spécialiser common_type pour les types T1 et T2 si

  • Au moins l'un des T1 et T2 dépend d'un type défini par l'utilisateur, et
  • std::decay est une transformation identité pour T1 et T2 .

Si une telle spécialisation possède un membre nommé type , celui-ci doit être un membre public et non ambigu qui désigne un type non qualifié cv et non référence vers lequel T1 et T2 sont explicitement convertibles. De plus, std :: common_type < T1, T2 > :: type et std :: common_type < T2, T1 > :: type doivent désigner le même type.

Un programme qui ajoute des spécialisations de common_type en violation de ces règles a un comportement indéfini.

Notez que le comportement d'un programme qui ajoute une spécialisation à tout autre template (sauf pour std::basic_common_reference ) (depuis C++20) de <type_traits> est indéfini.

Les spécialisations suivantes sont déjà fournies par la bibliothèque standard :

spécialise le trait std::common_type
(spécialisation de modèle de classe)
spécialise le trait std::common_type
(spécialisation de modèle de classe)
détermine le type commun de deux pair s
(spécialisation de modèle de classe)
détermine le type commun d'un tuple et d'un type tuple-like
(spécialisation de modèle de classe)
détermine le type commun d'un itérateur et d'un type basic_const_iterator adapté
(spécialisation de modèle de classe)

Implémentation possible

// modèle primaire (utilisé pour zéro type)
template<class...>
struct common_type {};
// un 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&> {};
    // implémentation C++11 :
    // 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> {};
}
// deux 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...> {};

Notes

Pour les types arithmétiques non soumis à la promotion, le type commun peut être considéré comme le type de l'expression arithmétique (éventuellement en mode mixte) telle que T0 ( ) + T1 ( ) + ... + Tn ( ) .

Exemples

Illustre l'arithmétique en mode mixte sur une classe définie par le programme :

#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);
}

Sortie :

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}

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Applicable à Comportement publié Comportement corrigé
LWG 2141 C++11 le type de résultat de l'opérateur conditionnel n'était pas dégradé a dégradé le type de résultat
LWG 2408 C++11 common_type n'était pas compatible SFINAE rendu compatible SFINAE
LWG 2460 C++11 common_type les spécialisations étaient quasi impossibles à écrire a réduit le nombre de
spécialisations nécessaires

Voir aussi

spécifie que deux types partagent un type commun
(concept)