Namespaces
Variants

User-defined conversion function

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Permet la conversion implicite ou la conversion explicite d'un type classe vers un autre type.

Table des matières

Syntaxe

La fonction de conversion est déclarée comme une fonction membre non statique ou un modèle de fonction membre sans paramètres, sans type de retour explicite, et avec un nom de la forme :

operator conversion-type-id (1)
explicit operator conversion-type-id (2) (depuis C++11)
explicit ( expression ) operator conversion-type-id (3) (depuis C++20)
1) Déclare une fonction de conversion définie par l'utilisateur qui participe à toutes les conversions implicites et conversions explicites .
2) Déclare une fonction de conversion définie par l'utilisateur qui participe uniquement à l'initialisation directe et aux conversions explicites .
3) Déclare une fonction de conversion définie par l'utilisateur qui est conditionnellement explicite .

conversion-type-id est un type-id sauf que les opérateurs de fonction et de tableau [] ou () ne sont pas autorisés dans son déclarateur (ainsi la conversion vers des types tels que pointeur vers tableau nécessite un alias de type/typedef ou un template d'identité : voir ci-dessous). Indépendamment du typedef, conversion-type-id ne peut pas représenter un type tableau ou un type fonction.

Bien que le type de retour ne soit pas autorisé dans la déclaration d'une fonction de conversion définie par l'utilisateur, la decl-specifier-seq de la grammaire de déclaration peut être présente et peut inclure tout spécificateur autre que type-specifier ou le mot-clé static . En particulier, outre explicit , les spécificateurs inline , virtual , constexpr (depuis C++11) , consteval (depuis C++20) , et friend sont également autorisés (notez que friend nécessite un nom qualifié : friend A :: operator B ( ) ; ).

Lorsqu'une telle fonction membre est déclarée dans la classe X, elle effectue la conversion de X vers conversion-type-id :

struct X
{
    // conversion implicite
    operator int() const { return 7; }
    // conversion explicite
    explicit operator int*() const { return nullptr; }
    // Erreur : opérateur de tableau non autorisé dans l'identifiant de type de conversion
//  operator int(*)[3]() const { return nullptr; }
    using arr_t = int[3];
    operator arr_t*() const { return nullptr; } // OK si effectué via typedef
//  operator arr_t () const; // Erreur : conversion vers tableau non autorisée dans tous les cas
};
int main()
{
    X x;
    int n = static_cast<int>(x);   // OK : définit n à 7
    int m = x;                     // OK : définit m à 7
    int* p = static_cast<int*>(x); // OK : définit p à null
//  int* q = x; // Erreur : aucune conversion implicite
    int (*pa)[3] = x;  // OK
}

Explication

La fonction de conversion définie par l'utilisateur est invoquée dans la deuxième étape de la conversion implicite , qui consiste en zéro ou un constructeur de conversion ou zéro ou une fonction de conversion définie par l'utilisateur.

Si les fonctions de conversion et les constructeurs de conversion peuvent tous deux être utilisés pour effectuer une conversion définie par l'utilisateur, les fonctions de conversion et les constructeurs sont tous deux pris en compte par la résolution de surcharge dans les contextes d' initialisation par copie et d' initialisation par référence , mais seuls les constructeurs sont pris en compte dans les contextes d' initialisation directe .

struct To
{
    To() = default;
    To(const struct From&) {} // constructeur de conversion
};
struct From
{
    operator To() const {return To();} // fonction de conversion
};
int main()
{
    From f;
    To t1(f);  // initialisation directe : appelle le constructeur
    // Note : si le constructeur de conversion n'est pas disponible, le constructeur de copie implicite
    // sera sélectionné, et la fonction de conversion sera appelée pour préparer son argument
//  To t2 = f; // initialisation par copie : ambiguë
    // Note : si la fonction de conversion est d'un type non-const, par exemple
    // From::operator To();, elle sera sélectionnée à la place du constructeur dans ce cas
    To t3 = static_cast<To>(f); // initialisation directe : appelle le constructeur
    const To& r = f;            // initialisation de référence : ambiguë
}

Fonction de conversion vers sa propre classe (éventuellement qualifiée cv) (ou vers une référence à celle-ci), vers la base de sa propre classe (ou vers une référence à celle-ci), et vers le type void peut être définie, mais ne peut pas être exécutée dans le cadre de la séquence de conversion, sauf, dans certains cas, via une résolution virtuelle :

struct D;
struct B
{
    virtual operator D() = 0;
};
struct D : B
{
    operator D() override { return D(); }
};
int main()
{
    D obj;
    D obj2 = obj; // n'appelle pas D::operator D()
    B& br = obj;
    D obj3 = br;  // appelle D::operator D() via dispatch virtuel
}

Il peut également être appelé en utilisant la syntaxe d'appel de fonction membre :

struct B {};
struct X : B
{
    operator B&() { return *this; };
};
int main()
{
    X x;
    B& b1 = x;                  // n'appelle pas X::operatorB&()
    B& b2 = static_cast<B&>(x); // n'appelle pas X::operatorB&
    B& b3 = x.operator B&();    // appelle X::operatorB&
}

Lors d'un appel explicite à la fonction de conversion, conversion-type-id est gourmand : il s'agit de la plus longue séquence de tokens qui pourrait potentiellement former un conversion-type-id (incluant les attributs, le cas échéant) (depuis C++11) :

& x.operator int * a; // erreur : analysé comme & (x.operator int*) a,
                      //           et non comme & (x.operator int) * a
operator int [[noreturn]] (); // erreur : attribut noreturn appliqué à un type

Le spécificateur de substitution auto peut être utilisé dans le conversion-type-id , indiquant un type de retour déduit :

struct X
{
    operator int(); // OK
    operator auto() -> short; // error: trailing return type not part of syntax
    operator auto() const { return 10; } // OK: deduced return type
    operator decltype(auto)() const { return 10l; } // OK: deduced return type
};

Remarque : une fonction de conversion template ne peut pas avoir un type de retour déduit.

(depuis C++14)

Les fonctions de conversion peuvent être héritées et peuvent être virtual , mais ne peuvent pas être static . Une fonction de conversion dans la classe dérivée ne masque pas une fonction de conversion dans la classe de base, sauf si elles convertissent vers le même type.

La fonction de conversion peut être une fonction membre template, par exemple, std::auto_ptr<T>::operator auto_ptr<Y> . Voir member template et template argument deduction pour les règles spéciales applicables.

Mots-clés

operator

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é
CWG 296 C++98 les fonctions de conversion pouvaient être statiques elles ne peuvent pas être déclarées statiques
CWG 2016 C++98 les fonctions de conversion ne pouvaient pas spécifier de types de retour,
mais les types sont présents dans conversion-type-id
les types de retour ne peuvent pas être spécifiés dans les
spécificateurs de déclaration des fonctions de conversion
CWG 2175 C++11 il n'était pas clair si le [ [ noreturn ] ] dans
operator int [ [ noreturn ] ] ( ) ; est analysé comme une partie du
noptr-declarator (du déclarateur de fonction) ou du conversion-type-id
il est analysé comme une partie du
conversion-type-id