为基于模板的代码生成更高质量错误消息的工具?

Ali*_*Ali 32 c++ templates stl custom-errors c++11

那些不需要这些工具的概念不是C++ 11的一部分.

有哪些生产质量工具可用于解析源自基于模板的代码的错误消息?Eclipse-CDT支持也很不错.:)

如果我放弃C++ 11,我对C++ 98有什么选择?


相关问题:

Die*_*ühl 17

让我们有一个答案(我标记了这个社区维基,所以我们一起得到了很好的回应)......

我工作很长时间以来模板和错误消息通常以某种方式得到改善:

  • 编写一堆错误会创建更多文本,但通常还包括用户正在查看的级别,这通常包括对实际问题的提示.假设编译器只看到翻译单元,那么就没有太多可以确定堆栈中哪个错误最适合用户的错误.
  • 使用概念检查器,即运行模板参数的所有必需成员并可能使用static_assert()模板作者生成错误消息的类或函数,为模板作者提供一种方法来告诉用户显然不适用的假设.
  • 告诉用户他写的类型而不是扩展所有typedef,因为编译器喜欢在最低级别看到也有帮助.clang相当擅长这个并且实际上给你错误信息,例如谈论std::string而不是将事物类型扩展到它最终的结果.

该技术的组合实际上导致例如clang创建相当不错的错误消息(即使它没有实现C++ 2011,但是,然而,没有编译器做,并且据我所知gcc和clang领先包装) .我知道其他编译器开发人员积极致力于改进模板错误消息,因为许多程序员发现模板实际上是一个巨大的飞跃,即使错误消息需要一些习惯.

像stlfilt face这样的问题工具是C++编译器和库正在积极开发中.这导致错误消息一直在移动,导致工具接收不同的输出.尽管编译器编写者在改进错误消息方面做得很好,但它确实使那些试图从他们得到的错误消息中工作的人更加努力.还有另一个方面:一旦检测到某个错误模式是常见的并且例如通过stlfilt获取(好吧,据我所知它没有主动维护)编译器编写者可能热衷于报告错误直接遵循这些模式,可能还提供编译器可用的附加信息,但之前不会发出.换句话说,我希望编译器编写者非常容易接受用户的报告,这些报告描述了常见的错误情况以及如何最好地报告它们.编译器编写者可能不会遇到错误本身,因为他们正在处理的代码实际上是C(例如gcc是用C实现的),或者因为他们习惯于某些模板技术而避免某些错误(例如,typename对于依赖类型的省略) .

最后,为了解决有关具体工具的问题:当我遇到一些抱怨某些模板实例化的编译器时,我正在使用的主要"工具"是使用不同的编译器!虽然情况并非总是如此,但通常一个编译器报告完全难以理解的错误消息,只有在看到另一个编译器的相当简洁的报告后才有意义(如果您感兴趣,我经常使用最新版本的gcc,clang和EDG为了这).然而,我并不知道一个像stlfilt一样容易打包的东西.


Ash*_*ain 9

我知道这可能没有您想要的那么有用,但我发现针对模板错误消息的最佳工具是知识.

很好地理解STL以及如何使用它将帮助您首先避免许多错误.其次,错误消息通常是指STL源中的函数 - 如果您大致了解如何实现STL,这对解密错误消息非常有用.最后,编译器制造商已经意识到这个问题并逐渐改进错误消息输出,因此您最好坚持使用最新版本的编译器.

这是一个模糊的模板错误的好例子:

std::vector<std::unique_ptr<int>> foo;
std::vector<std::unique_ptr<int>> bar = foo;
Run Code Online (Sandbox Code Playgroud)

unique_ptr不可复制,只能移动.因此,尝试将unique_ptr的向量分配给另一个向量将意味着向量源代码中的某处将尝试复制唯一指针.因此,错误将来自不属于您的代码,并因此抛出相当不透明的错误消息.理想的错误信息是

main.cpp(20):无法从'foo'构造'bar':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>          ]
Run Code Online (Sandbox Code Playgroud)

通过这个筛选有线索.第一部分引用了私有成员访问权限std::unique_ptr<int>.第二部分,如果单击到源行,则指向复制构造函数unique_ptr,该构造函数在private:说明符下声明.所以现在我们知道我们试图复制一个不允许的unique_ptr.第3,4和5节只是指向样板代码 - 它只是噪音.第6节说"看到对类模板实例化的引用'std :: _ Vector_val <_Ty,_Alloc>'正在编译".换句话说,这个错误发生在vector的模板代码中.最后一部分是最有趣的:它直接指向foo你自己的源代码中声明的行- 它找出了你自己的源代码中错误源自哪里!

所以加上线索:

  • 它起源于foo,
  • 它起源于矢量代码,
  • 它尝试复制不允许的unique_ptr.
  • 结论:载体试图复制其中一个元素,这是不允许的.检查代码foo并检查导致副本的任何内容.

由于编译器只指向foo的声明,如果赋值在源代码中很远,则会涉及一些搜索.这显然不是理想的,但我认为这种方法最终会让你有更多的机会来解决一般的错误.您将开始认识到这种错误转储意味着"您复制了一个unique_ptr".同样,我不是在捍卫它,它肯定需要改进 - 但我想现在输出中只有足够的信息,结合对STL的良好了解,可以解决问题.


Reu*_*ais 5

我发现 Clang 可以为高度模板化的代码生成最好的错误消息。当然,大多数情况下冗长是不可避免的,但大多数时候它仍然比 GCC 或 MSVC 更好。以下是 AshleysBrain 发布的示例代码的 Clang 错误消息:

$ 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.
Run Code Online (Sandbox Code Playgroud)

它仍然又长又难看,但在我看来,关于问题所在/问题所在更加清楚。