[英]Prevent undesired conversion in constructor
根据这里 , 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
};
不,他们不一样。 如果选择了该构造函数,则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
他们不一样。
Z z = 1LL;
以上版本适用于非显式版本,但不适用于显式版本。
声明Z
explicit的构造函数不会阻止构造函数参数从另一个类型转换。 它可以防止从参数到Z
的转换,而无需显式调用构造函数。
下面是显式构造函数调用的示例。
Z z = Z(1LL);
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
的混合仅在您的4个版本中留下Z z=Z(1LL)
有效。
(以上假设有效副本或移动ctor;如果不是,则用Z z=Z(...)
替换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 未使用function-specifier 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.