I want to extend a natvis visualizer for a (C++) template class. Is there a way to display a type name of the first template parameter?
It would be great for boost::variant<int,bool> v; v=1;
to display 1 (int)
or something like that
If you want to show $T1
as a string, wrap it with "
. For example, for
<DisplayString>{*($T1*)storage_.data_.buf} {"$T1"}</DisplayString>
in your case you will see 1 "int"
In my opinion the best solution is to use the standard C++17 std::variant
. MSVC comes with natvis for this type so that you have a pretty view of the value that is stored.
Here is some natvis code that I just wrote and tested:
<Type Name="boost::variant<*>">
<DisplayString Condition="which_==0">{*($T1*)storage_.data_.buf}</DisplayString>
<DisplayString Condition="which_==1" Optional="true">{*($T2*)storage_.data_.buf}</DisplayString>
<DisplayString Condition="which_==2" Optional="true">{*($T3*)storage_.data_.buf}</DisplayString>
<DisplayString Condition="which_==3" Optional="true">{*($T4*)storage_.data_.buf}</DisplayString>
<DisplayString Condition="which_==4" Optional="true">{*($T5*)storage_.data_.buf}</DisplayString>
<DisplayString Condition="which_==5" Optional="true">{*($T6*)storage_.data_.buf}</DisplayString>
<DisplayString Condition="which_==6" Optional="true">{*($T7*)storage_.data_.buf}</DisplayString>
<Expand>
<Item Name="which">which_</Item>
<Item Name="value0" Condition="which_==0">*($T1*)storage_.data_.buf</Item>
<Item Name="value1" Condition="which_==1" Optional="true">*($T2*)storage_.data_.buf</Item>
<Item Name="value2" Condition="which_==2" Optional="true">*($T3*)storage_.data_.buf</Item>
<Item Name="value3" Condition="which_==3" Optional="true">*($T4*)storage_.data_.buf</Item>
<Item Name="value4" Condition="which_==4" Optional="true">*($T5*)storage_.data_.buf</Item>
<Item Name="value5" Condition="which_==5" Optional="true">*($T6*)storage_.data_.buf</Item>
<Item Name="value6" Condition="which_==6" Optional="true">*($T7*)storage_.data_.buf</Item>
</Expand>
</Type>
It works for any boost::variant<type_or_types>
.
It has a DisplayString
that takes the variant's member storage_
and extracts the buffer buf
. The address of the buffer is then cast to a pointer to the type that was provided to std::variant
. As you can see in my code which_
is zero based, whereas the template parameters are 1 based. I am not interested in the address but in the value, so I am adding a *
in front of the value.
I also added an Expand
section so that you can expand a variant. This allows me to show which_
and to show the value again - this time the column Type
will show the correct type as you can see in my screen capture (for the variant itself the type is displayed as boost::variant<…>
and I do not know how to add the type name into the DisplayString
).
Please note that the Optional="true"
are required because otherwise we would get a parsing error in cases where less than 7 type parameters are passed (as in boost::variant<int,bool>
and natvis does not have a $T7
.
If you need more template parameters, you can easily extend the code.
If you want the DisplayString
to also shows the index (as an explicit value or coded into the name value…
), you can easily change it accordingly as in
<DisplayString Condition="which_==0">{{which={which_} value0={*($T1*)storage_.data_.buf}}}</DisplayString>
Last but not least please note that I did not test very much and that I did not look into boost::variant
into detail. I saw that storage_
has members suggesting that there is some alignment in place. So it might not be sufficient to just use storage_.data_.buf
. It might be necessary to adjust the pointer depending on the alignment being used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With