我有一个大致像这样的数据结构
struct Column
{
void* data;
};
template <class... T>
struct Table
{
size_t count;
std::vector<Column> columns; // columns.size() == sizeof...(T)
};
并且我正尝试通过以下方式对其进行可视化
+ Table
+ Column 0
item 1
item 2
...
+ Column 1
item 1
item 2
...
这是我到目前为止所拥有的:
<Type Name="Table<*>">
<Expand>
<Synthetic Name="Column 0">
<Expand>
<ArrayItems>
<Size>count</Size>
<ValuePointer>($T1*) columns[0].data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
<Synthetic Name="Column 1" Condition="columns.size() > 1">
<Expand>
<ArrayItems>
<Size>count</Size>
<ValuePointer>($T2*) columns[1].data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>
很明显,这种扩展的规模确实很差。我被降级为复制粘贴每一列的代码并添加Condition
来启用或禁用它。最后,我将获得最多支持的列数,之后,可视化将停止显示列。
有什么方法可以更智能地显示它吗?如果可以使用$T$i
之类的表达式索引模板参数,我可以想象有几种方法。
我真正想做的是这样的:
<Type Name="Table<*>">
<Expand>
<ArrayItems>
<Size>columns.size()</Size>
<Value>
<Synthetic Name="Column %i">
<Expand>
<ArrayItems>
<Size>count</Size>
<ValuePointer>($T$i2*) columns[$i2].data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Value>
</ArrayItems>
</Expand>
</Type>
答案 0 :(得分:1)
似乎唯一的选择是在代码中创建一个辅助类型,该类型进行递归模板扩展以逐个剥离模板参数。 并且您必须强制编译器实例化模板,以便natvis可以使用它。
我开始使用的数据
struct ColumnStorage
{
void* data;
};
struct TableStorage
{
size_t rowCount;
std::vector<ColumnStorage> columns;
};
template <class Table, class... TableColumns>
struct TableAccessor
{
TableStorage* tableStorage;
};
这就是我需要添加以获得体面的纳豆的
// The helper type that allows natvis to work. The first template parameter keeps track of the
// column index so we know where to index into TableStorage::columns. The second parameter isn't
// used here. The third parameter is the concrete types of each column.
template <int i, class Table, class... TableColumns>
struct NatvisColumnView;
template <class Table, class... TableColumns>
struct TableAccessor
{
TableStorage* tableStorage;
// Used by natvis to cast `this`
using NatvisView = NatvisColumnView<0, Table, TableColumns...>;
// Force the compiler to instantiate the template or it won't be available to natvis
TableAccessor() { (NatvisView*) this; }
};
// End the template recursion. Inherit from TableAccessor so that tableStorage can be used
template <int i, class Table, class Column>
struct NatvisColumnView<i, Table, Column> : TableAccessor<Table, Column> {};
// Recursive template to peel off column types one-by-one
template <int i, class Table, class FirstColumn, class... RestColumns>
struct NatvisColumnView<i, Table, FirstColumn, RestColumns...> : NatvisColumnView<i + 1, Table, RestColumns...>
{
using base = typename NatvisColumnView<i + 1, Table, RestColumns...>;
};
<Type Name="TableAccessor<*,*>">
<DisplayString>Table</DisplayString>
<Expand>
<Item Name="Count">tableStorage->rowCount</Item>
<!-- Cast `this` to the view type and use the for visualization -->
<ExpandedItem>*(NatvisView*) this</ExpandedItem>
</Expand>
</Type>
<!-- Bottom out the recursive view -->
<Type Name="NatvisColumnView<*,*,*>">
<DisplayString>NatvisColumnView</DisplayString>
<Expand>
<Synthetic Name="Column">
<Expand>
<ArrayItems>
<Size>tableStorage->rowCount</Size>
<ValuePointer>($T3*) tableStorage->columns[$T1].data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<!-- Display the first column then recurse -->
<Type Name="NatvisColumnView<*,*,*,*>">
<DisplayString>NatvisColumnView</DisplayString>
<Expand>
<Synthetic Name="Column">
<Expand>
<ArrayItems>
<Size>tableStorage->rowCount</Size>
<!-- Show the correct column using the column index (first template parameter)
and the column type (third template parameter) -->
<ValuePointer>($T3*) tableStorage->columns[$T1].data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
<ExpandedItem>*(base*) this</ExpandedItem>
</Expand>
</Type>
我尝试了其他各种方法,例如:
$T$i
,则无法正常工作。将来,我将直接使用natvis DLL,而不是大惊小怪地使用XML。