防止构造函数中出现不希望的转换
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
显式的构造函数不会阻止构造函数参数从其他类型转换。它防止在不显式调用构造函数的情况下从参数转换为Z
。
下面是显式构造函数调用的示例。
Z z = Z(1LL);
explicit
阻止到您的类型的隐式转换。
您的=delete
技术阻止了从long
到long long
的隐式转换。
这些几乎是不相关的。
有4种情况说明了差异:
Z z = 1L;
Z z = 1LL;
是从CCD_ 12和CCD_ 13到CCD_。
Z z = Z(1L);
Z z = Z(1LL);
是从CCD_ 15和CCD_ 16到CCD_。
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(...)
,得到相同的结论)。
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一个声明为但不包含的构造函数。函数说明符显式指定从其参数设置为其类的类型。这样的构造函数被称为转换构造函数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
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 防止构造函数中出现不希望的转换
- 希望我的代码逐行将矩阵元素转换为向量,它只将矩阵的最后一行显示为向量
- 在汇编中使用malloc分配的内存-希望在c++中将其转换为三维数组