Namespaces
Variants
Views
Actions

user-defined conversion

From cppreference.com
< cpp‎ | language
Revision as of 14:16, 9 February 2014 by Cubbi (Talk | contribs)

Enables implicit conversion from a class type to another type.

Syntax

Conversion function is declared like a non-static member function or member function template with no return type and with the name of the form:

operator conversion-type-id (1)
explicit operator conversion-type-id (2) (since C++11)
1) Declares a user-defined conversion function that participates in all implicit and explicit conversions
2) Declares a user-defined conversion function that participates in direct-initialization and explicit conversions only.

Function and array operators [] or () are not allowed in the declarator (thus conversion to types such as pointer to array requires a typedef: see below). Regardless of typedef, conversion-type-id cannot represent an array or a function type.


When such member function is declared in class X, it performs conversion from X to conversion-type-id:

struct X {
    //implicit conversion
    operator int() const { return 1; }
 
    // explicit conversion
    explicit operator int*() const { return nullptr; }
 
//   Error: array operator not allowed in conversion-type-id
//   operator int(*)[3]() const { return nullptr; }
    using arr_t = int[3];
    operator arr_t*() const { return nullptr; } // OK if done through typedef
//  operator arr_t () const; // Error: conversion to array not allowed in any case
};
 
int main()
{
    X x;
 
    int n = static_cast<int>(x);   // OK: sets n to 7
    int m = x;                     // OK: sets m to 7
 
    int* p = static_cast<int*>(x);  // OK: sets p to null
//  int* q = x; // Error: no implicit conversion
 
    int (*pa)[3] = x;  // OK
}

Explanation

User-defined conversion function is invoked on the second stage of the implicit conversion, which consists of zero or one single-argument (converting) constructor or zero or one user-defined conversion function.

If both conversion functions and converting constructors can be used to perform some user-defined conversion, the conversion functions and constructors are both considered by overload resolution in copy-initialization and reference-initialization contexts, but only the constructors are considered in direct-initialization contexts.

struct To {
    To() = default;
    To(const struct From&) {} // converting constructor
};
 
struct From {
    operator To() const {return To();} // conversion function
};
 
int main()
{
    From f;
    To t1(f); // direct-initialization: calls the constructor
// (note, if converting constructor is not available, implicit copy constructor
//  will be selected, and conversion function will be called to prepare its argument)
    To t2 = f; // copy-initialization: ambiguous
// (note, if conversion function is from a non-const type, e.g.
//  From::operator To();, it will be selected instead of the ctor in this case)
    To t3 = static_cast<To>(f); // direct-initialization: calls the constructor
    const To& r = f; // reference-initialization: ambiguous
}

Conversion function to its own (possibly cv-qualified) class (or to a reference to it), to the base of its own class (or to a reference to it), and to the type void can be defined, but can never be executed as part of the conversion sequence (it can still be called using member function call syntax or, in some cases, by virtual dispatch from a conversion sequence)

struct B {};
struct X : B {
    operator B&() { return *this; };
};
 
int main()
{
    X x;
    B& b1 = x;                  // does not call the user-defined conversion
    B& b2 = static_cast<B&>(x); // does not call the user-defined conversion
    B& b3 = x.operator B&();    // calls the user-defined conversion
}


When making an explicit call to the conversion function, the type-id is greedy: it is the longest possible sequence of tokens that is a valid type id:

& x.operator int * a; // parsed as & (x.operator int*) a
                      // not as & (x.operator int) * a

Conversion functions can be inherited and can be virtual, but cannot be static. A conversion function in the derived class does not hide a conversion function in the base class unless they are converting to the same type.

Conversion function can be a template member function, for example, std::auto_ptr<T>::operator auto_ptr<Y>. See member template for applicable special rules.