Предотвращение нежелательного преобразования в конструкторе
по данным здесь, 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
explicit не предотвращает преобразование аргумента конструктора из другого типа. Это предотвращает преобразование аргумента в 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
блокирует неявное преобразование для вашего типа.
код =delete
техника блокирует неявное преобразование из long
to long long
.
они почти не связаны.
есть 4 случая, которые иллюстрируют разницу:
Z z = 1L;
Z z = 1LL;
неявное преобразование из long
и long long
to 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
to 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;
}
ваш пример требует явного удаления.
Live:http://cpp.sh/4sqb
они не то же самое.
из стандартного рабочего проекта n4296
:
12.3.1 - [class.conv.ctor]:
1 конструктор объявлен без функция-спецификатор explicit указывает преобразование из типов его параметры к типу своего класса. Такой конструктор называется преобразование конструктор.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