6

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

Roman Khvostikov
  • 305
  • 3
  • 14

2 Answers2

13

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"

mr NAE
  • 3,144
  • 1
  • 15
  • 35
  • 2
    It's also possible to suppress the quotes, like this: {"$T1",sb}. – camenomizoratojoakizunewake Feb 06 '20 at 15:38
  • I want to achieve it also but failed. Eg: For `Foo` I have used `{{Foo < {"$T1"}, {$T2} >}}`. It has printed `Foo <[4], 2>`. I believe here `4` means the `byte` value of the type. I have another type `Foo, 2>`, is it possible to display the first parameter type for this class as like as `std::complex, 2>`? I am using `VSCode` in Linux system. – user10634362 Jun 02 '22 at 11:56
  • @user10634362, unfortunately, in your case you have to use MIEngine, which has a lot of limitations. I assume that ` – mr NAE Jun 02 '22 at 13:51
2

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&lt;*&gt;">
    <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.

View in Debugger

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
  • I actually didn't ask for visualizer for variant. I ask for the way to display template class parameter as a string – Roman Khvostikov Feb 09 '19 at 15:53
  • @RomanKhvostikov As you can see in my screen capture Visual Studio does display the type (as given as template Parameter). `v` is `boost::variant` and in case the first type is in use, it displays `value0 … … int`. The `int` in the third column is exactly the type provided as template parameter. If you want to add the type to the first or second column, then I must say that I doubt that this can be achieved. – Werner Henze Feb 09 '19 at 20:08