防止在构造函数中进行不需要的转换
Prevent undesired conversion in constructor
根据here,explicit
:
Specifies constructors and conversion operators (since C++11) that
don't allow implicit conversions or copy-initialization.
因此,这两种技术是否相同?
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
如果选择了构造函数,则不允许任何构造,并且可用于禁止隐式 argument 转换。
例如:
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
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;
}
您的示例需要显式删除。
它们不一样。
来自标准工作草案n4296
:
12.3.1 - [class.conv.ctor]:
1 A constructor declared without the function-specifier explicit specifies a conversion from the types of its
parameters to the type of its class. Such a constructor is called a converting constructor.
2 An explicit constructor constructs objects just like non-explicit constructors, but does so only where the
direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used. A default constructor
may be an explicit constructor; such a constructor will be used to perform default-initialization or 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
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 个版本中有效。
(以上假定有效的复制或移动构造函数;如果不是,则将 Z z=Z(...)
替换为 Z z(...)
并得出相同的结论)。
根据here,explicit
:
Specifies constructors and conversion operators (since C++11) that don't allow implicit conversions or copy-initialization.
因此,这两种技术是否相同?
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
如果选择了构造函数,则不允许任何构造,并且可用于禁止隐式 argument 转换。
例如:
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
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;
}
您的示例需要显式删除。
它们不一样。
来自标准工作草案n4296
:
12.3.1 - [class.conv.ctor]:
1 A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.2 An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used. A default constructor may be an explicit constructor; such a constructor will be used to perform default-initialization or 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
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 个版本中有效。
(以上假定有效的复制或移动构造函数;如果不是,则将 Z z=Z(...)
替换为 Z z(...)
并得出相同的结论)。