gpt4 book ai didi

c++ - 使用 std::type_info 在 natvis 中进行转换

转载 作者:行者123 更新时间:2023-12-04 11:17:00 25 4
gpt4 key购买 nike

在我工作的代码库中,我们使用 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 &amp; _Rep_mask"/>
<Intrinsic Name="type" Expression="(const type_info*)(_Storage._TypeData &amp; ~_Rep_mask)"/>
<Intrinsic Name="_Is_trivial" Expression="has_value() &amp;&amp; _Rep() == 0"/>
<Intrinsic Name="_Is_big" Expression="has_value() &amp;&amp; _Rep() == 1"/>
<Intrinsic Name="_Is_small" Expression="has_value() &amp;&amp; _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*)(&amp;_Storage._TrivialData)</Item>
<Item Name="[castable_ptr]" Condition="_Is_small()">(void*)(&amp;_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::any 被确定为一个强有力的先决条件(我可以理解),在微软改进 native 可视化器之前,下面可能是一个战术上的快速胜利。
在 natvis xml 配置文件中:

<Synthetic Name="[representation]" Condition="_Is_trivial()">
<!--<DisplayString>(Small/Trivial Object)</DisplayString>-->
<DisplayString>{_Storage._TrivialData._Val}</DisplayString>
</Synthetic>
<Synthetic Name="[representation]" Condition="_Is_small()">
<!--<DisplayString>{*displayStdAnyContent(*this)}</DisplayString>-->
<Expand>
<Item Name="[value]">*displayStdAnyContent(*this)</Item>
</Expand>
</Synthetic>

<Type Name="AnyCastedValue&lt;*&gt;">
<DisplayString>{value}</DisplayString>
<Expand>
<Item Name="[value]">value</Item>
</Expand>
</Type>
C++
//----------------------------------------------------------------------------------
class IAnyValue
{
public:
virtual ~IAnyValue() = default;
};

template <typename T>
struct AnyCastedValue final :public IAnyValue
{
AnyCastedValue(const T& pi_value) :value(pi_value) {}

T value;
};

struct NonCastableValue final :public IAnyValue
{
static constexpr auto message = "I'm not castable! Please register my type!";
};

//----------------------------------------------------------------------------------
class IAnyCaster
{
public:
virtual std::unique_ptr<IAnyValue> castValue(const std::any& pi_any) const = 0;
virtual ~IAnyCaster() = default;
};

template <typename T>
class AnyCaster final :public IAnyCaster
{
public:
AnyCaster() = default;

virtual std::unique_ptr<IAnyValue> castValue(const std::any& pi_any) const override
{
return std::make_unique<AnyCastedValue<T>>(std::any_cast<T>(pi_any));
}
};

//----------------------------------------------------------------------------------
class AnyCasterService final :public std::unordered_map<std::string, std::unique_ptr<IAnyCaster>>
{
public:
AnyCasterService()
{
//here we register the types you would like be able to watch under the debugger
registerType<int>();
registerType<std::string>();
}

std::unique_ptr<IAnyValue> castValue(const std::any& pi_any) const
{
auto im = find(pi_any.type().name());
if (im != end())
{
return im->second->castValue(pi_any);
}
else return std::make_unique<NonCastableValue>();
}

private:
template <typename T>
void registerType()
{
this->insert(std::make_pair(typeid(T).name(),std::make_unique<AnyCaster<T>>()));
}
};

//----------------------------------------------------------------------------------
std::unique_ptr<IAnyValue> displayStdAnyContent(const std::any& pi_any)
{
static const AnyCasterService s_service;
return s_service.castValue(pi_any);
}
我在 VS2017 v15.9.8 下验证了这个提议
请记住,Natvis 只能根据您的需要(显式用户调用)在运行时评估该方法。
std::any l_any;
l_any = 5;
l_any = std::string("it works!");
watch

关于c++ - 使用 std::type_info 在 natvis 中进行转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59285956/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com