Предотвратить нежелательное преобразование в конструкторе

В соответствии с Вот, 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
};

17

Решение

Они не идентичны.

Z z = 1LL;

Вышесказанное работает с неявной версией, но не с явной версией.

Объявив конструктор Z явный не предотвращает преобразование аргумента конструктора из другого типа. Это предотвращает преобразование аргумента в Z без вызова конструктора явно.

Ниже приведен пример явного вызова конструктора.

Z z = Z(1LL);
17

Другие решения

Нет, они не одинаковы. 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
24

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(...) и результат тот же вывод).

5

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

2

Они не то же самое.

Из стандартного рабочего проекта 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
1
По вопросам рекламы [email protected]