15 Special member functions [special]

15.3 Conversions [class.conv]

Преобразование типов объектов класса может определяться конструкторами и функциями преобразования. Эти преобразования вызываются user-defined conversions и используются для неявных преобразований типов (Clause [conv]), для initializationи для явных преобразований типов ([expr.cast], [expr.static.cast]).

Пользовательские преобразования применяются только в том случае, если они однозначны ([class.member.lookup], [class.conv.fct]). Конверсии подчиняются access control rules. Контроль доступа применяется после разрешения неоднозначности ([basic.lookup]).

[ Note: См. [over.match] Обсуждение использования преобразований в вызовах функций, а также примеры ниже. ]end note

Максимум одно определяемое пользователем преобразование (конструктор или функция преобразования) неявно применяется к одному значению. [Example:

struct X {
  operator int();
};

struct Y {
  operator X();
};

Y a;
int b = a;          // error, a.operator X().operator int() not tried
int c = X(a);       // OK: a.operator X().operator int()

end example]

Пользовательские преобразования используются неявно, только если они однозначны. Функция преобразования в производном классе не скрывает функцию преобразования в базовом классе, если две функции не преобразуются в один и тот же тип. Функция overload resolution выбирает лучшую функцию преобразования для выполнения преобразования. [Example:

struct X {
  operator int();
};

struct Y : X {
    operator char();
};

void f(Y& a) {
  if (a) {          // ill-formed: X​::​operator int() or Y​::​operator char()
  }
}

end example]

15.3.1 Conversion by constructor [class.conv.ctor]

Конструктор, объявленный без, function-specifier explicit определяет преобразование типов его параметров (если есть) в тип своего класса. Такой конструктор называется converting constructor. [Example:

struct X {
    X(int);
    X(const char*, int =0);
    X(int, int);
};

void f(X arg) {
  X a = 1;          // a = X(1)
  X b = "Jessie";   // b = X("Jessie",0)
  a = 2;            // a = X(2)
  f(3);             // f(X(3))
  f({1, 2});        // f(X(1,2))
}

end example]

[ Note: Явный конструктор создает объекты так же, как неявные конструкторы, но делает это только там, direct-initialization где явно используются синтаксис или приведение типов ([expr.static.cast], [expr.cast]); см. также [over.match.copy]. Конструктор по умолчанию может быть явным конструктором; такой конструктор будет использоваться для выполнения инициализации по умолчанию или value-initialization. [Example:

struct Z {
  explicit Z();
  explicit Z(int);
  explicit Z(int, int);
};

Z a;                            // OK: default-initialization performed
Z b{};                          // OK: direct initialization syntax used
Z c = {};                       // error: copy-list-initialization
Z a1 = 1;                       // error: no implicit conversion
Z a3 = Z(1);                    // OK: direct initialization syntax used
Z a2(1);                        // OK: direct initialization syntax used
Z* p = new Z(1);                // OK: direct initialization syntax used
Z a4 = (Z)1;                    // OK: explicit cast used
Z a5 = static_cast<Z>(1);       // OK: explicit cast used
Z a6 = { 3, 4 };                // error: no implicit conversion

end example] ]end note

Неявный конструктор копирования / перемещения ([class.copy]) - это конструктор преобразования. [ Note: Неявно объявленный конструктор копирования / перемещения не является явным конструктором; он может вызываться для неявного преобразования типов. ]end note

15.3.2 Conversion functions [class.conv.fct]

Функция-член класса X без параметров с именем формы

conversion-function-id:
	operator conversion-type-id
conversion-type-id:
	type-specifier-seq conversion-declaratoropt
conversion-declarator:
	ptr-operator conversion-declaratoropt

указывает преобразование из X в тип, указанный в conversion-type-id. Такие функции называются conversion functions. A decl-specifierв decl-specifier-seq функции преобразования (если есть) не должно быть ни a, defining-type-specifierни static. Тип функции преобразования ([dcl.fct]) - «функция, не возвращающая никаких параметров conversion-type-id». Функция преобразования никогда не используется для преобразования объекта (возможно, квалифицированного cv) в (возможно, квалифицированный cv) объект того же типа (или ссылку на него) в базовый класс (возможно, квалифицированный cv) этого типа (или ссылка на него) или на (возможно cv-квалифицированный) void.117 [Example:

struct X {
  operator int();
  operator auto() -> short;     // error: trailing return type
};

void f(X a) {
  int i = int(a);
  i = (int)a;
  i = a;
}

Во всех трех случаях присвоенное значение будет преобразовано в X​::​operator int(). ]end example

Функция преобразования может быть explicit, и в этом случае она рассматривается только как определяемое пользователем преобразование для direct-initialization. В противном случае пользовательские преобразования не ограничиваются использованием в назначениях и инициализациях. [Example:

class Y { };
struct Z {
  explicit operator Y() const;
};

void h(Z z) {
  Y y1(z);          // OK: direct-initialization
  Y y2 = z;         // ill-formed: copy-initialization
  Y y3 = (Y)z;      // OK: cast notation
}

void g(X a, X b) {
  int i = (a) ? 1+a : 0;
  int j = (a&&b) ? a+b : i;
  if (a) {
  }
}

end example]

Не conversion-type-id должен представлять тип функции или тип массива. In conversion-type-id a conversion-function-id - это самая длинная последовательность токенов, которая могла бы образовать conversion-type-id. [ Note: Это предотвращает двусмысленность между оператором-декларатором * и его эквивалентами-выражениями. [Example:

&ac.operator int*i; // syntax error:
                    // parsed as: &(ac.operator int *)i
                    // not as: &(ac.operator int)*i

Это * декларатор указателя, а не оператор умножения. ] Это правило также предотвращает двусмысленность атрибутов. [end exampleExample:

operator int [[noreturn]] ();   // error: noreturn attribute applied to a type

end example] ]end note

Функции преобразования наследуются.

Функции преобразования могут быть виртуальными.

В шаблоне функции преобразования не должно быть файла deduced return type. [Example:

struct S {
  operator auto() const { return 10; }      // OK
  template<class T>
  operator auto() const { return 1.2; }     // error: conversion function template
};

end example]

Эти преобразования считаются стандартными в целях разрешения перегрузки ([over.best.ics], [over.ics.ref]) и, следовательно, инициализации ([dcl.init]) и explicit casts. Преобразование в void не вызывает никакой функции преобразования ([expr.static.cast]). Даже если они никогда не вызываются напрямую для выполнения преобразования, такие функции преобразования могут быть объявлены и потенциально могут быть достигнуты посредством вызова функции виртуального преобразования в базовом классе.