隐式转换在现代C++是好是坏?
Are implicit conversions good or bad in modern C++?
在此提案中:
N3830 作用域内资源 - 标准库的通用 RAII 包装器
提出了一个scoped_resource
的 RAII 包装器。
在第 4 页上,有一些这样的代码:
auto hFile = std::make_scoped_resource( ... ); ... // cast operator makes it seamless to use with other APIs needing a HANDLE ReadFile(hFile, ...);
Win32 APIReadFile()
采用原始HANDLE
参数,而不是hFile
scoped_resource
的实例,因此为了使上述代码正常工作,有一个由scoped_resource
实现的隐式强制转换运算符。
但是,"现代"建议不是为了避免这种隐式转换吗?
例如,ATL/MFCCString
有一个隐式转换(强制转换运算符)到LPCTSTR
(const char/wchar_t*
,即原始 C 字符串指针),而不是 STL 字符串具有显式c_str()
方法。
类似地,像unique_ptr
这样的智能指针有一个显式的get()
方法来访问底层包装的指针;反对隐式转换的建议似乎也出现在这篇博文中:
读者问答:为什么现代智能指针不隐式转换为*?
那么,这些隐式转换(如ATL/MFCCString
和新提出的scoped_resource
)是否适用于现代C++?
从编码的角度来看,我会说能够简单地将 RAII 包装器(无论是CString
还是scoped_resource
)传递给期望"原始"参数(如原始 C 字符串指针或原始句柄)的 C API,依靠隐式转换,而无需调用一些.GetString()
/.get()
方法,似乎非常方便。
以下是引自C++入门第 5 版。
注意:避免过度使用转换函数
与使用重载运算符一样,明智地使用转换运算符可以 大大简化了类设计人员的工作,并使类的使用更加容易。 但是,某些转换可能会产生误导。转换运算符是 当类类型之间没有明显的单一映射时具有误导性 和转换类型。
例如,考虑一个表示日期的类。我们可能会认为 提供从
Date
到int
的转换是个好主意。然而 转换函数应返回什么值?该函数可能会返回 年、月和日的十进制表示形式。例如,1989 年 7 月 30 日可能表示为 int 值19800730。或者,转换运算符可能会返回一个 int,表示自某个纪元点(如 1970 年 1 月 1 日)以来经过的天数。这两种转换都具有理想的属性,即以后的日期对应于较大的整数,因此任何一种都可能有用。问题是 对象类型为
Date
,值类型为int
。在这种情况下,最好不要 以定义转换运算符。相反,类应该定义一个或 更多的普通成员以这些不同的形式提取信息。
所以,我可以说的是,在实践中,类应该很少提供转换运算符。很多时候,如果转换自动发生,用户更有可能感到惊讶,而不是得到 转换的存在。但是,此规则有一个重要的例外 thumb:类定义转换为bool
的情况并不少见。 在标准的早期版本中,想要定义转换为的类 bool 面临一个问题:因为 bool 是一个算术类型,一个类类型的对象 转换为 bool 可用于需要算术类型的任何上下文。 这种转换可能会以令人惊讶的方式发生。特别是,如果istream
有一个 转换为bool
,以下代码将编译:
int i = 42;
cin << i; // this code would be legal if the conversion to bool were not explicit!
应使用explicit
转换运算符。下面是一个小例子:
class small_int
{
private:
int val;
public:
// constructors and other members
explicit operator int() const { return this->val; }
}
。并在程序中:
int main()
{
SmallInt si = 3; // ok: the SmallInt constructor is not explicit
si + 3; // error: implicit is conversion required, but operator int is explicit
static_cast<int>(si) + 3; // ok: explicitly request the conversion
return 0;
}
我认为隐式转换对应用程序程序员来说是好的/方便的,但对库开发人员来说是坏的,因为它们引入了复杂性和其他问题: 一个很好的例子是隐式转换和模板推导之间的相互作用。
从库的角度来看,将语言功能限制为最小集更容易。为此,您甚至可以说,如果删除一些重载和默认参数,库更容易维护。对于应用程序程序员来说不太方便,但歧义和复杂性较小。
因此,这实际上是在方便和简单之间做出的选择。
它在很大程度上取决于确切的转换类型,但一般来说,在某些领域,隐式转换可能会带来问题,而显式转换可能不会。
通常,在编程中显式执行任何操作都是一种更安全的方法。
关于一般C++,特别是隐式和显式转换,有一个很好的信息来源。
- 防止主数据类型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图像"中的"颜色"转换为整数格式
- 是否可以从int转换为enum类类型
- 了解 GLM- openGL 中的相机转换
- 将无符号char*转换为std::istream*C++