Функциональные локальные структуры/классы и файлы natvis

Скажем, мне нужно следующую структуру:

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)));
}

И следующее в моем файле natvis:

<Type Name="TSH2SizedArray&lt;*,*&gt;">
    <DisplayString>TotalItemCount={ElemCount} (via natvis debug)</DisplayString>
    <Expand>
      <Item Name="TotalItemCount">ElemCount</Item>
      <ArrayItems>
        <Size>ElemCount</Size>
        <ValuePointer>($T1*)Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

Сегодня я понял, что средство отладки, предоставляемое файлом natvis, в этой ситуации не работает:

void MyFunc()
{
    struct CMyLocalStruct
    {
        int ValueA;
        int ValueB;
    };
    TSH2SizedArray<CMyLocalStruct, 256> Array;
    Array.Add(CMyLocalStruct(1,2));
}

Но работает в том:

// File scope
struct CMyLocalStruct
{
     int ValueA;
     int ValueB;
};
void MyFunc()
{

    TSH2SizedArray<CMyLocalStruct, 256> Array;
    Array.Add(CMyLocalStruct(1,2));
}

Если у кого-то есть решение, я был бы очень благодарен, потому что это своего рода ограничение. Но мне это кажется багом.


person OeilDeLance    schedule 26.09.2017    source источник
comment
Вы говорите, что это не работает, но не говорите, почему.   -  person John Zwinck    schedule 26.09.2017


Ответы (1)


Локальная структура — это тип, который компилятор помечает по-разному. Итак, MSVC дает ему имя вроде:

`MyFunc'::`2'::CMyLocalStruct

Натвис смотрит на линию

($T1*))Data

и заменяет $T1 параметром шаблона, который в данном случае является локальной структурой и получает:

(`MyFunc'::`2'::CMyLocalStruct*)Data

Наконец он жалуется:

Error: identifier "`MyFunc'" is undefined

Что для меня выглядит как ошибка, потому что он должен продолжать читать остальную часть типа, но я не уверен.


Обходной путь, который я нашел, состоит в том, чтобы объявить псевдоним для параметра шаблона в структуре с оператором using:

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;
};

А затем используйте псевдоним:

  <Type Name="TSH2SizedArray&lt;*,*&gt;">
    <DisplayString>TotalItemCount={ElemCount} (via natvis debug)</DisplayString>
    <Expand>
      <Item Name="TotalItemCount">ElemCount</Item>
      <ArrayItems>
        <Size>ElemCount</Size>
        <ValuePointer>(myType*)Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

Наконец, natvis показывает правильную интерпретацию локального типа и, по иронии судьбы, показывает имя локального типа, которое не мог интерпретировать ранее: natvis показывает значения

person wally    schedule 26.09.2017
comment
Спасибо за качественный ответ, он объясняет, почему это не работает. - person OeilDeLance; 27.09.2017
comment
Однако использование ‹ValuePointer›Data‹/ValuePointer› не является решением, потому что весь смысл в том, чтобы привести указатель uint8 к указателю CMyLocalStruct. Знаете, чтобы упростить отладку массива? - person OeilDeLance; 27.09.2017
comment
Чтобы он отображался в часах как массив CMyLocalStruct - person OeilDeLance; 27.09.2017
comment
@OeilDeLance Хорошо, я вижу, что для правильной интерпретации массива требуется локальный тип. Я опубликовал обходной путь, но не знаю, можете ли вы обновить класс. Другой, менее безопасный обходной путь может состоять в том, чтобы объявить эквивалентную фиктивную структуру в вашем собственном заголовочном файле и использовать ее, если вы не можете изменить структуру. - person wally; 27.09.2017