Предотвращение нежелательного преобразования в конструкторе
Согласно здесь, explicit
:
Таким образом, являются ли эти два метода идентичными?Задает конструкторы и операторы преобразования (начиная с C++11), которые не допускайте неявных преобразований или инициализации копирования.
struct Z {
// ...
Z(long long); // can initialize with a long long
Z(long) = delete; // but not anything smaller
};
struct Z {
// ...
explicit Z(long long); // can initialize ONLY with a long long
};
5 ответов:
Они не идентичны.
Z z = 1LL;
Вышеописанное работает с неявной версией, но не с явной версией.
Объявление конструктора
Z
явным не препятствует преобразованию аргумента конструктора из другого типа. Это предотвращает преобразование аргумента вZ
без явного вызова конструктора.Ниже приведен пример явного вызова конструктора.
Z z = Z(1LL);
Нет, это не одно и то же.
explicit
запрещает неявные преобразования к этому типу, если этот конструктор выбран - неявные преобразования в аргументах не имеют значения.delete
запрещает любую конструкцию, если этот конструктор выбран, и может использоваться для запрета неявного преобразования аргумента .Так, например:
struct X { explicit X(int ) { } }; void foo(X ) { } foo(4); // error, because X's constructor is explicit foo(X{3}); // ok foo(X{'3'}); // ok, this conversion is fine
, который отделен от
delete
ING конструктора:Эти два метода также ортогональны. Если вы хотите, чтобы тип не был неявно-конвертируемые и только конструктивные из точноstruct Y { Y(int ) { } Y(char ) = delete; }; void bar(Y ) { } bar(4); // ok, implicit conversion to Y since this constructor isn't explicit bar('4'); // error, this constructor is deleted bar(Y{'4'}); // error, doesn't matter that we're explicit
int
, Вы можете сделать и то и другое:struct W { explicit W(int ) { } template <class T> W(T ) = delete; }; void quux(W ); quux(4); // error, constructor is explicit quux('4'); // error, constructor is deleted quux(4L); // error, constructor is deleted quux(W{'4'}); // error, constructor is deleted quux(W{5}); // ok
explicit
блокирует неявное преобразование в ваш тип .Ваша
Они почти не связаны между собой. Есть 4 случая, которые иллюстрируют это различие:=delete
техника блокирует неявное преобразование изlong
вlong long
.Z z = 1L; Z z = 1LL;
- это неявное преобразование из
long
иlong long
вZ
.Z z = Z(1L); Z z = Z(1LL);
- это явное преобразование из
long
иlong long
вZ
.
explicit Z(long long)
блоки:Z z = 1L; Z z = 1LL;
Пока
Z(long)=delete
блоки:Z z = 1L; Z z = Z(1L);
Обратите внимание, что смесь
explicit Z(long long)
позволяетZ z = Z(1L)
, потому что преобразование изlong
вlong long
неявно, но не связано с явным преобразованием вZ
, которое происходит впоследствии.explicit
и=delete
оставляет толькоZ z=Z(1LL)
действительными среди ваших 4 версий.(вышеизложенное предполагает допустимую копию или перемещение ctor; если нет, замените
Z z=Z(...)
наZ z(...)
и получите те же выводы).
struct Zb { Zb(long long) {}; // can initialize with a long long Zb(long) = delete; // but not anything smaller }; struct Za { // ... explicit Za(long long) {}; // can initialize ONLY with a long long }; int main() { Za((long long)10); // works Za((long)10); // works Zb((long long)10); // works Zb((long)10); // does not work return 0; }
Ваш пример требует явного удаления.
Жить: http://cpp.sh/4sqb
Это не одно и то же.
Из стандартного рабочего проекта
n4296
:
12.3.1 - [class.conv.ctor]:
1 конструктор, объявленный Без спецификатора функции, явно определяет преобразование из типов его параметры к типу своего класса. Такой конструктор называетсяпреобразующим конструктором .2 явный конструктор создает объекты точно так же, как и неявные конструкторы, но делает это только там, где синтаксис прямой инициализации (8.5) или где явно используются приведения (5.2.9, 5.4). Конструктор по умолчанию может быть явным конструктором; такой конструктор будет использоваться для выполнения инициализации по умолчанию или valueinitialization (8.5).
С последующим примером каждого из них соответственно:
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)) }
С явным конструктором:
struct Z { explicit Z(); explicit Z(int); explicit Z(int, int); }; Z a; // OK: default-initialization performed 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