User-defined conversion function
Позволяет неявное преобразование или явное преобразование из классового типа в другой тип.
Содержание |
Синтаксис
Функция преобразования объявляется как нестатическая функция-член или шаблон функции-члена без параметров, без явного возвращаемого типа и с именем вида:
operator
conversion-type-id
|
(1) | ||||||||
explicit
operator
conversion-type-id
|
(2) | (начиная с C++11) | |||||||
explicit (
expression
)
operator
conversion-type-id
|
(3) | (начиная с C++20) | |||||||
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>
. Смотрите
шаблоны-члены
и
вывод аргументов шаблона
для соответствующих специальных правил.
Ключевые слова
Отчёты о дефектах
Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам 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 |