3

Ok, so I've got a pretty straightforward class making use of type erasure, using a shared pointer.

class Prop
{
    struct PropConcept
    {
        virtual ~PropConcept() {}
    };
    template<typename T>
    struct PropModel : PropConcept
    {
        PropModel(const T& t) : prop(t) { }
        PropModel() {}
        virtual ~PropModel() {}
    private:
        T prop;
    };

    std::shared_ptr<PropConcept> prop;
public:

    template<typename T>
    Prop(const T& obj) : prop(new PropModel<T>(obj)) { }
    Prop() {};
};

No issues here, however due to how it works, the debugger shows the complete chain from Prop, to the std::shared_ptr(PropContent), to PropModel, and finally the underlying templated prop, which contains the actual data.

What I'd like to do - is write a natvis rule to display that underlying data, instead of the entire chain. Unfortunately, the furthest I've gotten is to dereference the pointer, which just leaves me with the PropConcept struct that it points to.

<Type Name="Prop">
   <DisplayString>{*prop}</DisplayString>
   <Expand>
      <Item Name="prop">(*prop)</Item>
   </Expand>
</Type>

So of course, my question is, how do I traverse the "tree" to get to the "prop" member of the PropModel struct? It doesn't matter if the class itself needs to be tweaked, or if it's just pure natvis - just as long as the type erasure remains, and I don't have to expand 4 items to get to the data.

Thanks in advance for any help.

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
Digital_Utopia
  • 816
  • 8
  • 17

2 Answers2

3

It is as easy as adding logic for Prop::PropModel:

<Type Name="Prop::PropModel&lt;*&gt;">
  <DisplayString>{prop}</DisplayString>
  <Expand>
    <Item Name="prop">prop</Item>
  </Expand>
</Type>

I have tested with

Prop p1{};
Prop p2{ 42 };
Prop p3{ std::string{"x"} };

and the display is

enter image description here

As you can see your code for type Prop is not optimal. It could check for an empty shared_ptr and have an extra display for that. My logic for Prop::PropModel can also be improved if you want some type to be displayed differently, for example ints being displayed decimal.

By the way, you should enable MSVC code analysis. Your code triggers some warnings.

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
  • Thank you! After a few days of no answer I played with it a bit more, and got scary close to this answer - only overlooking PropModel expand tag. Also, thanks for the advice - I'll be sure to check code analysis before this code ever leaves my computer. I agree, I should handle an empty pointer, but if it ever is, that indicates a bigger problem. So at least for now, the default will do. I'll include my final result as an answer, but marking yours as correct. – Digital_Utopia Jan 06 '19 at 21:22
1

I eventually got a lot closer to Werner Henze's answer, but said answer supplied the final info I needed. For completion's sake, below is my final natvis for this class, as well as a picture of how it appears in the debugger. In this case, the shared_ptr points to a std::vector<int>

  <Type Name="Prop">
    <DisplayString>{*prop}</DisplayString>
    <Expand>
      <ExpandedItem>(*prop)</ExpandedItem>
    </Expand>
  </Type>

  <Type Name="Prop::PropModel&lt;*&gt;">
    <DisplayString>{prop}</DisplayString>
    <Expand>
      <ExpandedItem>prop</ExpandedItem>
    </Expand>
  </Type>

Which results in this...

Digital_Utopia
  • 816
  • 8
  • 17