В соответствии с Вот, 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
};
Они не идентичны.
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
конструктор:
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
в long long
,
Это почти не связано.
Есть 4 случая, которые иллюстрируют разницу:
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). Конструктор по умолчанию
может быть явным конструктором; такой конструктор будет использоваться для выполнения инициализации по умолчанию или инициализации значения
(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