【发布时间】:2019-12-11 12:34:18
【问题描述】:
在我正在工作的代码库中,我们使用std::any 而不是void* 来通过一些通用的非模板代码传递类。具体来说,我们使用 Visual Studio 2019、它的编译器和标准库。
为了可视化std::any,微软已经给出了natvis:
<Type Name="std::any">
<Intrinsic Name="has_value" Expression="_Storage._TypeData != 0"/>
<Intrinsic Name="_Rep" Expression="_Storage._TypeData & _Rep_mask"/>
<Intrinsic Name="type" Expression="(const type_info*)(_Storage._TypeData & ~_Rep_mask)"/>
<Intrinsic Name="_Is_trivial" Expression="has_value() && _Rep() == 0"/>
<Intrinsic Name="_Is_big" Expression="has_value() && _Rep() == 1"/>
<Intrinsic Name="_Is_small" Expression="has_value() && _Rep() == 2"/>
<DisplayString Condition="!has_value()">[empty]</DisplayString>
<DisplayString Condition="_Is_trivial() || _Is_small()">[not empty (Small)]</DisplayString>
<DisplayString Condition="_Is_big()">[not empty (Large)]</DisplayString>
<Expand>
<Synthetic Name="has_value">
<DisplayString>{has_value()}</DisplayString>
</Synthetic>
<Synthetic Name="type" Condition="has_value()">
<DisplayString>{type()}</DisplayString>
</Synthetic>
<Synthetic Name="[representation]" Condition="_Is_trivial()">
<DisplayString>(Small/Trivial Object)</DisplayString>
</Synthetic>
<Synthetic Name="[representation]" Condition="_Is_small()">
<DisplayString>(Small Object)</DisplayString>
</Synthetic>
<Synthetic Name="[representation]" Condition="_Is_big()">
<DisplayString>(Dynamic Allocation)</DisplayString>
</Synthetic>
</Expand>
</Type>
但是,这最终向我们显示了(Small Object),而不是我们存储在其中的std::string。
我已经设法用一些额外的行来扩展它以获取指向数据的指针:
<Item Name="[castable_ptr]" Condition="_Is_trivial()">(void*)(&_Storage._TrivialData)</Item>
<Item Name="[castable_ptr]" Condition="_Is_small()">(void*)(&_Storage._SmallStorage._Data)</Item>
<Item Name="[castable_ptr]" Condition="_Is_big()">(void*)(_Storage._BigStorage._Ptr)</Item>
但是,这会将数据显示为 void*,您必须手动将其转换为实际类型 std::string* 的指针。
然而,这个std::any 实现/可视化也带有std::type_info。 (参见字段:类型),它知道我们拥有哪种底层类型。
有没有办法使用这个std::type_info 以便(void*) 可以替换为实际存储类型的转换?
编辑: Visual Studio 为以下类型提供的信息示例:{mydll.dll!class std::tuple<__int64,double,double,double> 'RTTI Type Descriptor'} {...}
在将地址显式转换为 std::type_info* 时,我可以在调试器中访问 _Data,其中包含 _DecoratedName (.?AV?$tuple@_JNNN@std@@) 和 _UndecoratedName (nullptr)。
不幸的是,我似乎不知道如何编写一个利用这些信息的演员表。
【问题讨论】:
-
std::type_info包含字段name,你能到达吗? -
就像@Swift-FridayPie 说的那样,有没有办法使用
std::any.type().name()方法,也许与std::any_cast<type T>()结合使用? -
@Swift-FridayPie 所有我能找到的都在编辑中提到
-
@arc-menace 我不认为
std::any_cast可以在NatVis中使用 -
注意:目前,我已经记录了 STL 实现的一个错误:github.com/microsoft/STL/issues/929
标签: c++ visual-studio c++17 natvis