Let's say I have to following struct:
template<class Type, int32 SIZE>
struct TSH2SizedArray
{
inline void Add(const Type & Value);
inline Type & operator[](int32 Index);
inline const Type & operator[](int32 Index)const;
private:
uint8 Data[SIZE * sizeof(Type)];
int32 ElemCount = 0;
};
template<class Type, int32 SIZE>
inline void TSH2SizedArray<Type, SIZE>::Add(const Type & Value)
{
assert(0 <= ElemCount && ElemCount < SIZE);
*((Type*)(Data + ElemCount++ * sizeof(Type))) = Value;
}
template<class Type, int32 SIZE>
inline Type & TSH2SizedArray<Type, SIZE>::operator[](int32 Index)
{
assert(0 <= Index && Index < ElemCount);
return *((Type*)(Data + Index * sizeof(Type)));
}
template<class Type, int32 SIZE>
inline const Type & TSH2SizedArray<Type, SIZE>::operator[](int32 Index)const
{
assert(0 <= Index && Index < ElemCount);
return *((Type*)(Data + Index * sizeof(Type)));
}
And the following in my natvis file:
<Type Name="TSH2SizedArray<*,*>">
<DisplayString>TotalItemCount={ElemCount} (via natvis debug)</DisplayString>
<Expand>
<Item Name="TotalItemCount">ElemCount</Item>
<ArrayItems>
<Size>ElemCount</Size>
<ValuePointer>($T1*)Data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
Today I realized that the debug aid provided by the natvis file doesn't work in this situation:
void MyFunc()
{
struct CMyLocalStruct
{
int ValueA;
int ValueB;
};
TSH2SizedArray<CMyLocalStruct, 256> Array;
Array.Add(CMyLocalStruct(1,2));
}
But works in that one:
// File scope
struct CMyLocalStruct
{
int ValueA;
int ValueB;
};
void MyFunc()
{
TSH2SizedArray<CMyLocalStruct, 256> Array;
Array.Add(CMyLocalStruct(1,2));
}
If someone has a solution I would be super grateful because that's kind of limiting. But it looks like a bug to me though.
The local struct is a type that is labeled differently by the compiler. So MSVC gives it a name like:
`MyFunc'::`2'::CMyLocalStruct
Natvis looks at the line
($T1*))Data
and replaces the $T1
with the template parameter, which is the local struct in this case and gets:
(`MyFunc'::`2'::CMyLocalStruct*)Data
Finally it complains:
Error: identifier "`MyFunc'" is undefined
Which to me looks like a bug, because it should keep reading the rest of the type, but I'm not sure.
A workaround that I've found is to declare an alias for the template parameter in the struct with a using
statement:
template<class Type, int32 SIZE>
struct TSH2SizedArray
{
inline void Add(const Type & Value);
inline Type & operator[](int32 Index);
inline const Type & operator[](int32 Index)const;
using myType = Type; // natvis will interpret this correctly
private:
uint8 Data[SIZE * sizeof(Type)];
int32 ElemCount = 0;
};
And then use the alias:
<Type Name="TSH2SizedArray<*,*>">
<DisplayString>TotalItemCount={ElemCount} (via natvis debug)</DisplayString>
<Expand>
<Item Name="TotalItemCount">ElemCount</Item>
<ArrayItems>
<Size>ElemCount</Size>
<ValuePointer>(myType*)Data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
Finally natvis does show the correct interpretation for the local type and, ironically, it shows the name of the local type that it could not interpret earlier: