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

Позволяет неявное преобразование или явное преобразование из классового типа в другой тип.

Содержание

Синтаксис

Функция преобразования объявляется как нестатическая функция-член или шаблон функции-члена без параметров, без явного возвращаемого типа и с именем вида:

operator conversion-type-id (1)
explicit operator conversion-type-id (2) (начиная с C++11)
explicit ( expression ) operator conversion-type-id (3) (начиная с C++20)
1) Объявляет пользовательскую функцию преобразования, которая участвует во всех неявных и явных преобразованиях .
2) Объявляет пользовательскую функцию преобразования, которая участвует только в direct-initialization и explicit conversions .
3) Объявляет пользовательскую функцию преобразования, которая является условно explicit .

conversion-type-id является type-id за исключением того, что операторы функций и массивов [] или () не допускаются в его деклараторе (таким образом, преобразование в типы, такие как указатель на массив, требует использования псевдонима типа/typedef или шаблона идентичности: см. ниже). Независимо от typedef, conversion-type-id не может представлять тип массива или тип функции.

Хотя возвращаемый тип не допускается в объявлении пользовательской функции преобразования, decl-specifier-seq из грамматики объявлений может присутствовать и может включать любой спецификатор, кроме type-specifier или ключевого слова static . В частности, помимо explicit , также разрешены спецификаторы inline , virtual , constexpr (начиная с C++11) , consteval (начиная с C++20) и friend (обратите внимание, что для friend требуется квалифицированное имя: friend A :: operator B ( ) ; ).

Когда такая функция-член объявлена в классе X, она выполняет преобразование из X в conversion-type-id :

struct X
{
    // неявное преобразование
    operator int() const { return 7; }
    // явное преобразование
    explicit operator int*() const { return nullptr; }
    // Ошибка: оператор массива не разрешен в conversion-type-id
//  operator int(*)[3]() const { return nullptr; }
    using arr_t = int[3];
    operator arr_t*() const { return nullptr; } // OK если выполнено через typedef
//  operator arr_t () const; // Ошибка: преобразование в массив не разрешено ни в каком случае
};
int main()
{
    X x;
    int n = static_cast<int>(x);   // OK: устанавливает n в 7
    int m = x;                     // OK: устанавливает m в 7
    int* p = static_cast<int*>(x); // OK: устанавливает p в null
//  int* q = x; // Ошибка: нет неявного преобразования
    int (*pa)[3] = x;  // OK
}

Объяснение

Пользовательская функция преобразования вызывается на втором этапе неявного преобразования , который состоит из нуля или одного преобразующего конструктора или нуля или одной пользовательской функции преобразования.

Если и функции преобразования, и преобразующие конструкторы могут быть использованы для выполнения некоторого пользовательского преобразования, то и функции преобразования, и конструкторы рассматриваются overload resolution в контекстах copy-initialization и reference-initialization , но только конструкторы рассматриваются в контекстах direct-initialization .

struct To
{
    To() = default;
    To(const struct From&) {} // конструктор преобразования
};
struct From
{
    operator To() const {return To();} // функция преобразования
};
int main()
{
    From f;
    To t1(f);  // прямая инициализация: вызывает конструктор
    // Примечание: если конструктор преобразования недоступен, будет выбран неявный конструктор копирования,
    // и функция преобразования будет вызвана для подготовки его аргумента
//  To t2 = f; // копирующая инициализация: неоднозначность
    // Примечание: если функция преобразования из неконстантного типа, например
    // From::operator To();, она будет выбрана вместо конструктора в этом случае
    To t3 = static_cast<To>(f); // прямая инициализация: вызывает конструктор
    const To& r = f;            // инициализация ссылки: неоднозначность
}

Функция преобразования в собственный (возможно, cv-квалифицированный) класс (или в ссылку на него), в базовый класс собственного класса (или в ссылку на него) и в тип void может быть определена, но не может быть выполнена как часть последовательности преобразований, за исключением, в некоторых случаях, через виртуальную диспетчеризацию:

struct D;
struct B
{
    virtual operator D() = 0;
};
struct D : B
{
    operator D() override { return D(); }
};
int main()
{
    D obj;
    D obj2 = obj; // не вызывает D::operator D()
    B& br = obj;
    D obj3 = br;  // вызывает D::operator D() через виртуальную диспетчеризацию
}

Это также можно вызвать с использованием синтаксиса вызова функции-члена:

struct B {};
struct X : B
{
    operator B&() { return *this; };
};
int main()
{
    X x;
    B& b1 = x;                  // не вызывает X::operatorB&()
    B& b2 = static_cast<B&>(x); // не вызывает X::operatorB&
    B& b3 = x.operator B&();    // вызывает X::operatorB&
}

При явном вызове функции преобразования, conversion-type-id является жадным: это самая длинная последовательность токенов, которая может образовать conversion-type-id (включая атрибуты, если они есть) (начиная с C++11) :

& x.operator int * a; // ошибка: разбирается как & (x.operator int*) a,
                      //           а не как & (x.operator int) * a
operator int [[noreturn]] (); // ошибка: атрибут noreturn применён к типу

Заполнитель auto может использоваться в conversion-type-id , указывая на выводимый тип возвращаемого значения :

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

Примечание: шаблон функции преобразования conversion function template не может иметь выводимый тип возвращаемого значения.

(начиная с C++14)

Функции преобразования могут наследоваться и могут быть virtual , но не могут быть static . Функция преобразования в производном классе не скрывает функцию преобразования в базовом классе, если они не преобразуют в один и тот же тип.

Функция преобразования может быть шаблонной функцией-членом, например, std::auto_ptr<T>::operator auto_ptr<Y> . Смотрите шаблоны-члены и вывод аргументов шаблона для соответствующих специальных правил.

Ключевые слова

operator

Отчёты о дефектах

Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 296 C++98 функции преобразования могли быть статическими они не могут быть объявлены как статические
CWG 2016 C++98 функции преобразования не могли указывать возвращаемые типы,
но типы присутствуют в conversion-type-id
возвращаемые типы не могут быть указаны в
спецификаторах объявления функций преобразования
CWG 2175 C++11 было неясно, является ли [ [ noreturn ] ] в
operator int [ [ noreturn ] ] ( ) ; частью
noptr-declarator (декларатора функции) или conversion-type-id
это анализируется как часть
conversion-type-id