Namespaces
Variants
Views
Actions

user-defined conversion

From cppreference.com
< cpp‎ | language
Revision as of 18:28, 3 January 2014 by D41D8CD98F (Talk | contribs)

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
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
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

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.
conversion-type-id - any type-id except function and array

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 not allowed in conversion-type-id
//   operator int(*)[3]() const { return nullptr; }
    using ptr_t = int(*)[3];
    operator ptr_t() const { return nullptr; } // OK if done through typedef
};
 
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

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>