std::any 必须使用类型擦除来实现。那是因为它可以存储 any 类型并且不能是模板。目前 C++ 中没有其他功能可以实现这一点。
这意味着std::any 将存储一个类型擦除的指针,void* 和std::any_cast 将该指针转换为指定的类型,仅此而已。它只是在使用 typeid 之前进行完整性检查,以检查您将其转换为的类型是否是存储在 any 中的类型。
使用当前实现是不可能允许隐式转换的。考虑一下(暂时忽略typeid 检查)。
std::any_cast<long>(a);
a 存储 int 而不是 long。 std::any 应该怎么知道?它可以将其void* 转换为指定的类型,取消引用并返回它。将指针从一种类型转换为另一种类型是严格的别名违规并导致 UB,所以这是个坏主意。
std::any 必须存储存储在其中的对象的实际类型,这是不可能的。您现在不能在 C++ 中存储类型。它可以维护一个类型列表以及它们各自的typeids 并切换它们以获取当前类型并执行隐式转换。但是对于您要使用的每个 单一类型,没有办法做到这一点。用户定义的类型无论如何都不起作用,您必须依靠诸如宏之类的东西来“注册”您的类型并为其生成适当的 switch case1。
可能是这样的:
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());
// and so on. Add your macro magic here.
// What should happen if a type is not registered?
}
这是一个好的解决方案吗?不,到目前为止。切换成本很高,而 C++ 的口号是“你不用为你不使用的东西付费”所以不,目前没有办法实现这一点。该方法也是“hacky”并且非常脆弱(如果您忘记注册类型会发生什么)。简而言之,这样做可能带来的好处一开始就不值得。
是否有允许隐式转换的解决方法(以防 std::any 持有的确切类型未知)?
是的,使用上面提到的宏寄存器方法1自己实现std::any(或类似类型)和std::any_cast。我不会推荐它。如果您不知道也无法知道std::any 存储的类型并需要访问它,则可能存在设计缺陷。
1:实际上不知道这是否可能,我在宏(ab)使用方面不是那么好。您还可以为自定义实现硬编码类型或使用单独的工具。