Подтвердить что ты не робот

Инструменты для создания более качественных сообщений об ошибках для кода на основе шаблонов?

Concepts, что бы сделать эти инструменты ненужными, не является частью С++ 11.

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

  • Clang утверждает, что дает выразительную диагностику, хотя важно Возможности С++ 11 пока недоступны.

  • colorgcc, похоже, заброшен с 1999 года.

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

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


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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Хорошее понимание 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:. Итак, теперь мы знаем, что мы попытались скопировать уникальный_ptr, который не разрешен. Разделы 3, 4 и 5 просто указывают на шаблонный код - это просто шум. В разделе 6 говорится, что "см. Ссылку на экземпляр шаблона класса" std:: _ Vector_val < _Ty, _Alloc > 'скомпилировано ". Другими словами, эта ошибка произошла в коде векторного шаблона. Последний раздел наиболее интересен: он прямо указывает на строку, объявляющую foo в вашем собственном исходном коде - он выяснил, где в вашем собственном исходном коде возникла ошибка!

Итак, добавляем подсказки:

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

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

Ответ 3

Я нашел 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.

Он по-прежнему длинный и уродливый, но, на мой взгляд, гораздо яснее в отношении того, что/где проблема.