c++ - 基于整数类型的两个类之间的隐式转换
问题描述
我有一个类A
,它为整数类型提供构造函数,以及B
为相同整数类型提供隐式转换运算符的类。但是,如果我调用一个函数来接受对具有类A
实例的类的引用B
,则编译将失败。我本来期望将 class 隐式转换为 classB
的构造函数接受的类型A
。当然,如果我在A
接受类中添加一个构造函数B
,一切都很好。这种行为是有意的吗?请查看下面的示例。
#include <iostream>
class B
{
public:
B() = default;
B(const std::uint8_t &val) : mVal(val) {}
std::uint8_t get() const { return mVal; }
operator std::uint8_t() const { return mVal; }
private:
std::uint8_t mVal;
};
class A
{
public:
A() = default;
A(const std::uint8_t &val) : mVal(val) {}
// No problem if this exists
// A(const B &b) : mVal(b.get()) {}
std::uint8_t get() const { return mVal; }
private:
std::uint8_t mVal;
};
void func(const A &a)
{
std::cout << static_cast<int>(a.get()) << std::endl;
}
int main(int, char*[])
{
std::uint8_t val = 0xCE;
A a(val);
B b(val);
func(val); // fine
func(a); // fine
func(b); // error
}
解决方案
C++ 中有一条规则,即没有隐式转换将使用两个用户定义的转换。
这是因为这种“长距离”转换可能会导致极其令人惊讶的结果。
如果您希望能够从任何可以转换为 a 的东西转换,uint8_t
您可以执行以下操作:
template<class IntLike,
std::enable_if_t<std::is_convertible_v<IntLike, std::uint8_t>, bool> =true,
std::enable_if_t<!std::is_same_v<A, std::decay_t<IntLike>>, bool> =true
>
A( IntLike&& intlike ):A( static_cast<std::uint8_t>(std::forward<IntLike>(intlike)) )
{}
或者您可以B
在uint8_t
要转换为A
.
您可以做类似的事情,在B
其中创建一个template<class T, /*SFINAE magic*/> operator T
可以转换为任何可以由uint8_t
.
这个晦涩的代码:
std::enable_if_t<std::is_convertible_v<IntLike, std::uint8_t>, bool> =true,
std::enable_if_t<!std::is_same_v<A, std::decay_t<IntLike>>, bool> =true
存在以确保仅当我们要转换的类型具有我们想要的属性时才使用重载。
第一个enable_if
子句声明我们只想要可以转换为uint8_t
. 第二个状态我们不希望这个构造函数用于类型A
本身,即使它通过了第一个。
每当您为类型创建转发引用隐式构造函数时,第二个子句非常需要,否则您会遇到其他一些令人惊讶的问题。
使用的技术称为 SFINAE 或替换失败不是错误。当IntType
推导出一个类型并且这些测试失败时,这些子句中存在替换失败。通常这会导致错误,但在评估模板重载时它不是错误,因为 SFINAE;相反,它只是阻止此模板在重载决议中被考虑。
推荐阅读
- javascript - 使用 onclick 从另一个函数中调用函数
- bash - If-Statement 疯了(还是我?)
- reactjs - Webpack + react-native-web:错误:无法解析“BoundingDimensions”
- c - char 和 char* 在内存中的对齐方式
- android - 如何将对象随机放置在 Sceneform 平面上?
- python - Bottle 框架资源利用率
- excel - 如何仅将包含字母“A”的某些列/数据字段引入数据透视表?
- git - 如何将子文件夹的副本复制到 Git 中的单独存储库中?
- ionic-framework - httpClient 的问题我收到此错误
- python - 除非从根目录运行,否则 Python 库不会加载