Инструменты для создания более качественных сообщений об ошибках для кода на основе шаблона? - PullRequest
32 голосов
/ 08 января 2012

Концепции , которые делают эти инструменты ненужными, не являются частью C ++ 11 .

  • STLFilt был бы одним из вариантов, но он больше не поддерживается.

  • Clang утверждает, что проводит экспресс-диагностику, хотя важные функции C ++ 11 пока недоступны.

  • colorgcc представляется заброшенным с 1999 года.

Какие средства обеспечения качества производства доступны для расшифровки сообщений об ошибках, возникающих из кода на основе шаблонов? Поддержка Eclipse-CDT тоже подойдет. :)

Если я откажусь от C ++ 11, какие у меня есть варианты для C ++ 98?


Похожие вопросы:

Ответы [ 3 ]

17 голосов
/ 09 января 2012

Давайте попробуем ответить (я отметил эту вики сообщества, чтобы мы вместе получили хороший ответ) ...

Я давно работаю с шаблонами и сообщениями об ошибках, как правило, так или иначе улучшилось:

  • Запись стека ошибок создает намного больше текста, но также обычно включает в себя уровень, на который смотрит пользователь, и, как правило, включает подсказку о том, какова реальная проблема. Учитывая, что компилятор видит только брошенный на него модуль перевода, мало что можно сделать, чтобы определить, какая ошибка в стеке является наиболее подходящей для пользователя.
  • Использование концептуальных контролеров, то есть классов или функций, которые осуществляют все необходимые члены аргументов шаблона и, возможно, генерирование сообщений об ошибках с использованием static_assert(), дает автору шаблона способ рассказать пользователям о предположениях, которые явно не выполняются.
  • Сообщать пользователю о типах, которые он пишет, а не расширять все typedef, которые компилятор хотел бы видеть на самом низком уровне, также помогает. Clang довольно хорош в этом и на самом деле выдает сообщения об ошибках, например говорить о std::string, а не расширять тип вещей до того, чем они заканчиваются.

Сочетание техники фактически вызывает, например, clang для создания вполне приличного сообщения об ошибке (даже если он еще не реализует C ++ 2011; тем не менее, никакой компилятор этого не делает, и, насколько я могу судить, gcc и clang возглавляют пакет). Я знаю, что другие разработчики компиляторов активно работают над улучшением сообщений об ошибках шаблонов, так как многие программисты обнаружили, что шаблоны на самом деле являются огромным скачком вперед, даже несмотря на то, что к сообщениям об ошибках нужно немного привыкнуть.

Одной из проблемных инструментов, таких как stlfilt face, является то, что компиляторы и библиотеки C ++ находятся в активной разработке. Это приводит к постоянному смещению сообщений об ошибках, в результате чего инструмент получает разные выходные данные. Хотя хорошо, что авторы компиляторов работают над улучшением сообщений об ошибках, это, безусловно, усложняет жизнь людям, которые пытаются работать с полученными сообщениями об ошибках. В этом есть и другая сторона: как только определенная схема ошибок обнаруживается как распространенная и обнаруживается, например, stlfilt (ну, насколько я знаю, он активно не поддерживается) авторы компилятора, вероятно, заинтересованы в том, чтобы напрямую сообщать об ошибках, следующих этим шаблонам, возможно, также предоставляя дополнительную информацию, доступную для компилятора, но не выпущенную ранее. Иными словами, я ожидал бы, что составители компиляторов весьма восприимчивы к отчетам пользователей, описывающим типичные ситуации с ошибками и способы их наилучшего представления. Авторы компилятора могут сами не сталкиваться с ошибками, потому что код, над которым они работают, на самом деле является C (например, gcc реализован на C) или потому, что они так используются для определенных методик шаблонов, что они избегают определенных ошибок (например, пропуск typename для зависимые типы).

Наконец, для решения вопроса о конкретных инструментах: основной «инструмент», который я использую, когда застреваю в компиляторе, жалующемся на некие экземпляры шаблона, - это использование разных компиляторов! Хотя это не всегда так, но часто один компилятор сообщает о совершенно непонятных сообщениях об ошибках, которые имеют смысл только после просмотра довольно сжатого отчета от другого компилятора (если вам интересно, я регулярно использую последние версии gcc, clang и EDG за это). Однако я не знаю о готовой упаковке, такой как stlfilt.

9 голосов
/ 15 января 2012

Я знаю, что это может быть не так полезно, как вы хотели, но я нашел лучший инструмент против сообщений об ошибках шаблона: знание .

Хорошее понимание STL и какего использование поможет вам избежать множества ошибок.Во-вторых, часто сообщения об ошибках относятся к функциям в источнике STL - если у вас есть приблизительное представление о том, как реализован STL, это может быть чрезвычайно полезно для расшифровки того, о чем идет сообщение об ошибке.Наконец, создатели компиляторов знают об этой проблеме и постепенно улучшают вывод сообщений об ошибках, поэтому вам лучше придерживаться последней версии вашего компилятора.

Вот хороший пример неясной ошибки шаблона:

std::vector<std::unique_ptr<int>> foo;
std::vector<std::unique_ptr<int>> bar = foo;

unique_ptr не копируется, его можно только перемещать.Поэтому попытка назначить вектор unique_ptr другому вектору будет означать, что где-то в исходном коде вектора будет пытаться скопировать уникальный указатель.Следовательно, ошибка будет возникать из кода, который вам не принадлежит, и в результате выдает довольно непрозрачное сообщение об ошибке.Идеальное сообщение об ошибке:

main.cpp (20): невозможно создать 'bar' из 'foo': тип шаблона foo не копируется

Вместо этогоVS2010 выдает следующую ошибку:

1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(48): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory(2347) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr'
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(197) : see reference to function template instantiation 'void std::_Construct<std::unique_ptr<_Ty>,const std::unique_ptr<_Ty>&>(_Ty1 *,_Ty2)' being compiled
1>          with
1>          [
1>              _Ty=int,
1>              _Ty1=std::unique_ptr<int>,
1>              _Ty2=const std::unique_ptr<int> &
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(196) : while compiling class template member function 'void std::allocator<_Ty>::construct(std::unique_ptr<int> *,const _Ty &)'
1>          with
1>          [
1>              _Ty=std::unique_ptr<int>
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector(421) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<int>
1>          ]
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector(481) : see reference to class template instantiation 'std::_Vector_val<_Ty,_Alloc>' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<int>,
1>              _Alloc=std::allocator<std::unique_ptr<int>>
1>          ]
1>         main.cpp(19) : see reference to class template instantiation 'std::vector<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<int>
1>          ]

Просеивая это, есть подсказки.Первый раздел ссылается на частный доступ std::unique_ptr<int>.Второй раздел, если вы щелкнете по строке исходного текста, указывает на конструктор копирования unique_ptr, который объявлен под спецификатором private:.Итак, теперь мы знаем, что пытались скопировать unique_ptr, что запрещено.Разделы 3, 4 и 5 просто указывают на стандартный код - это просто шум.В разделе 6 говорится «смотрите ссылку на экземпляр шаблона класса 'std :: _ Vector_val <_Ty, _Alloc>', который компилируется».Другими словами, эта ошибка произошла в коде шаблона вектора.Последний раздел наиболее интересен: он непосредственно указывает на строку, в которой в вашем собственном исходном коде указано foo - он выяснил, откуда в вашем собственном исходном коде возникла ошибка!

Итак, добавьте подсказки:

  • Он исходит из foo,
  • Он исходит из векторного кода,
  • Он пытается скопировать unique_ptr, что не разрешено.
  • Вывод:вектор пытался скопировать один из своих элементов, что недопустимо.Просмотрите код для foo и проверьте, нет ли причин, вызывающих копию.

Поскольку компилятор указал только на объявление foo, если присваивание находится далеко в исходном коде, потребуется некоторая охота.Это, очевидно, не идеально, но я думаю, что этот подход в конечном итоге дает вам больше шансов исправить ошибки в целом.Вы начнете распознавать такой тип дампа ошибок, означающего «вы скопировали unique_ptr».Опять же, я не защищаю это, оно определенно нуждается в улучшении - но я думаю, что в наши дни просто достаточно информации в выводе, что в сочетании с хорошим знанием STL позволяет вам решить проблему.

4 голосов
/ 16 января 2012

Я обнаружил, что Clang генерирует лучшие сообщения об ошибках для сильно шаблонного кода. Конечно, многословие в большинстве случаев неизбежно, но в большинстве случаев оно все же лучше, чем GCC или MSVC. Вот сообщение об ошибке Clang для примера кода, размещенного AshleysBrain:

$ clang++ -std=c++11 -stdlib=libc++ -o dummy dummy.cpp 
In file included from dummy.cpp:1:
In file included from /usr/include/c++/v1/vector:243:
In file included from /usr/include/c++/v1/__bit_reference:15:
In file included from /usr/include/c++/v1/algorithm:594:
/usr/include/c++/v1/memory:1425:36: error: calling a private constructor of class 'std::__1::unique_ptr<int,
      std::__1::default_delete<int> >'
                ::new ((void*)__p) _Tp(_STD::forward<_Args>(__args)...);
                                   ^
/usr/include/c++/v1/memory:1358:14: note: in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >
      >::__construct<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::unique_ptr<int,
      std::__1::default_delete<int> > &>' requested here
            {__construct(__has_construct<allocator_type, pointer, _Args...>(),
             ^
/usr/include/c++/v1/vector:781:25: note: in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >
      >::construct<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::unique_ptr<int,
      std::__1::default_delete<int> > &>' requested here
        __alloc_traits::construct(__a, _STD::__to_raw_pointer(this->__end_), *__first);
                        ^
/usr/include/c++/v1/vector:924:9: note: in instantiation of function template specialization
      'std::__1::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >,
      std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >
      >::__construct_at_end<std::__1::unique_ptr<int, std::__1::default_delete<int> > *>' requested here
        __construct_at_end(__x.__begin_, __x.__end_);
        ^
dummy.cpp:7:37: note: in instantiation of member function 'std::__1::vector<std::__1::unique_ptr<int,
      std::__1::default_delete<int> >, std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >
      >::vector' requested here
        std::vector<unique_ptr<int>> bar = foo;
                                           ^
/usr/include/c++/v1/memory:1997:5: note: declared private here
    unique_ptr(const unique_ptr&);
    ^
1 error generated.

Это все еще долго и некрасиво, но, на мой взгляд, гораздо яснее, в чем / где проблема.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...