std::any
必须使用类型抹除来实现。这是因为它可以存储任何类型,而且不能是一个模板。目前在C++中没有其他功能可以实现这一点。
这意味着std::any
将存储一个类型抹除指针void*
,而std::any_cast
将把该指针转换为指定的类型,然后就完成了。它只是在转换之前使用typeid
进行一致性检查,以检查您将其转换为的类型是否与存储在任何中的类型相同。
使用当前实现将无法允许隐式转换。暂时忽略typeid
检查,想想看。
std::any_cast<long>(a);
a
存储的是
int
而不是
long
。那么
std::any
怎么知道呢?它只能将其
void*
强制转换为指定的类型,然后解引用并返回它。从一个类型到另一个类型的指针强制转换属于严格别名违规,会导致未定义行为,所以这是一个不好的想法。
std::any
必须存储其中存储的实际对象类型,但这是不可能的。你现在无法在 C++ 中存储类型。 它可以维护一系列类型及其对应的
typeid
,并切换以获取当前类型并执行隐式转换。 但是,无法为您要使用的每个单个类型执行此操作。用户定义的类型无法正常工作,并且您必须依赖诸如宏之类的东西来“注册”您的类型并为其生成适当的开关案例
1。
也许可以尝试以下方式:
template<typename T>
T any_cast(const any &Any) {
const auto Typeid = Any.typeid();
if (Typeid == typeid(int))
return *static_cast<int *>(Any.ptr());
else if (Typeid == typeid(long))
return *static_cast<long *>(Any.ptr());
}
这是一个好的解决方案吗?远远不是。交换机成本高昂,而C++的口号是“你不会为你不使用的东西付费”,所以目前没有办法实现这一点。这种方法也很“hacky”并且非常脆弱(如果您忘记注册类型会发生什么)。简而言之,像这样做的可能好处不值得麻烦。
有没有解决方法可以允许隐式转换(在 std::any 持有的确切类型未知的情况下)?
是的,使用上述宏注册方法自己实现 std::any(或类似类型)和 std::any_cast。我不建议这样做。如果您不知道并且无法知道 std::any 存储什么类型,并且需要访问它,则可能存在设计缺陷。
1: 实际上不知道是否可能,在宏滥用方面我不太擅长。您还可以在您的自定义实现中硬编码您的类型,或者使用单独的工具。