36

これらのツールを不要にする概念は、C++11 の一部ではありません

  • STLFiltは 1 つのオプションでしたが、現在は維持されていません。

  • Clangは、重要なC++11 機能がまだ利用できないにもかかわらず、表現力豊かな診断を提供すると主張しています。

  • colorgccは 1999 年から廃止されたようです。

テンプレートベースのコードに起因するエラーメッセージを解読するために利用できる製品品質ツールは何ですか? Eclipse-CDT のサポートもいいでしょう。:)

C++11 をあきらめた場合、C++98 にはどのようなオプションがありますか?


関連する質問:

4

3 に答える 3

19

答えを突き詰めてみましょう (私はこのコミュニティ wiki にマークを付けたので、一緒に良い反応が得られます)...

私は長い間テンプレートを使用して作業しており、エラーメッセージは一般的に何らかの形で改善されています:

  • エラーのスタックを書き込むと、より多くのテキストが作成されますが、通常、ユーザーが見ているレベルも含まれます。これには通常、実際の問題が何であるかについてのヒントが含まれます。コンパイラは翻訳単位が投げられていることしか認識していないため、スタック内のどのエラーがユーザーに最も適しているかを判断できることはあまりありません。
  • 概念チェッカー、つまり、テンプレート引数のすべての必要なメンバーを実行し、場合によっては を使用してエラー メッセージを生成するクラスまたは関数を使用するとstatic_assert()、テンプレートの作成者は、明らかに当てはまらない仮定についてユーザーに伝えることができます。
  • コンパイラが最下位レベルで見たいので、すべての typedef を展開するのではなく、ユーザーが記述した型についてユーザーに伝えることも役立ちます。clang はこれがかなり得意で、実際にエラー メッセージを表示std::stringします。

実際には、これらの手法の組み合わせにより、たとえば、clang はかなり適切なエラー メッセージを生成します (C++2011 をまだ実装していなくても、ただし、実装しているコンパイラはなく、私が知る限り、gcc と clang がパックをリードしています)。 . 他のコンパイラ開発者がテンプレート エラー メッセージの改善に積極的に取り組んでいることは知っています。多くのプログラマーは、エラー メッセージに慣れるには少し時間がかかるものの、テンプレートが実際には大きな飛躍を遂げていることを発見しています。

stlfilt のようなツールが直面する問題の 1 つは、C++ コンパイラとライブラリが活発に開発されていることです。これにより、エラー メッセージが常に変化し、ツールが異なる出力を受け取ることになります。コンパイラの作成者がエラー メッセージの改善に取り組むのは良いことですが、得られたエラー メッセージから作業を進めようとする人々の生活が困難になることは確かです。これには別の側面もあります。特定のエラーパターンが一般的であることが検出され、stlfilt などによって検出されると (私の知る限り、積極的に保守されていません)、コンパイラの作成者はおそらくエラーを報告することに熱心です。これらのパターンを直接たどることで、コンパイラーが利用できる追加情報を提供する可能性がありますが、以前は出力されませんでした。別の言い方をすれば、コンパイラの作成者は、一般的なエラー状況と、それらを報告するのに最適な方法を説明するユーザーからの報告を非常に受け入れやすいと思います。コンパイラの作成者は、作業しているコードが実際には C である (たとえば、gcc は C で実装されている) ため、または特定のエラーを回避するために特定のテンプレート手法に慣れているため (たとえば、typename依存型の場合)。

最後に、具体的なツールに関する質問に答えます。テンプレートのインスタンス化について不平を言うコンパイラーに行き詰まったときに使用する主な「ツール」は、さまざまなコンパイラーを使用することです! 常にそうであるとは限りませんが、あるコンパイラがまったく理解できないエラーメッセージを報告することがよくありますが、これは別のコンパイラからのかなり簡潔なレポートを見た後にのみ意味があります (興味がある場合に備えて、私は gcc、clang、および EDG の最近のバージョンを定期的に使用しています)このため)。ただし、stlfilt のように簡単にパッケージ化されていることは知りません。

于 2012-01-08T20:00:49.130 に答える
9

これはあなたが望むほど役に立たないかもしれませんが、テンプレートのエラー メッセージに対する最良のツールはknowledgeであることがわかりました。

STL とその使用方法をよく理解することは、そもそも多くのエラーを回避するのに役立ちます。第 2 に、エラー メッセージは STL ソース内の関数を参照することがよくあります。STL がどのように実装されているかを大まかに把握している場合、これはエラー メッセージの内容を解読するのに非常に役立ちます。最後に、コンパイラ メーカーはこの問題を認識しており、エラー メッセージの出力を徐々に改善しているため、最新バージョンのコンパイラを使用することをお勧めします。

以下は、あいまいなテンプレート エラーの良い例です。

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

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>          ]

これをふるいにかけると、手がかりがあります。最初のセクションは、 のプライベート メンバー アクセスを参照しますstd::unique_ptr<int>。ソース行までクリックすると、2 番目のセクションはunique_ptr、指定子の下で宣言されている のコピー コンストラクターを指しprivate:ます。これで、許可されていない unique_ptr をコピーしようとしたことがわかりました。セクション 3、4、および 5 は定型コードを示しているだけです。これは単なるノイズです。セクション 6 には、「コンパイルされているクラス テンプレートのインスタンス化 'std::_Vector_val<_Ty,_Alloc>' への参照を参照してください」と記載されています。つまり、このエラーは vector のテンプレート コードで発生しました。最後のセクションは最も興味深いものです。これfooは、独自のソース コードで宣言している行を直接指しています。これにより、独自のソース コードのどこからエラーが発生したかがわかります。

したがって、手がかりを追加します。

  • それはfooに由来し、
  • それはベクトルコードに由来し、
  • 許可されていない unique_ptr をコピーしようとしています。
  • 結論: ベクターはその要素の 1 つをコピーしようとしましたが、これは許可されていません。コードをfoo確認して、コピーの原因となっているものがないか確認します。

コンパイラは foo の宣言のみを指すため、代入がソース コード内で遠く離れている場合、ハンティングが必要になります。これは明らかに理想的ではありませんが、最終的にはこのアプローチにより、一般的に間違いを修正する可能性が高くなると思います。この種のエラー ダンプが「unique_ptr をコピーした」ことを意味することを認識するようになります。繰り返しますが、私はそれを擁護しているわけではありません。間違いなく改善が必要ですが、最近では、STL の十分な知識と組み合わせて問題を解決できる十分な情報が出力に含まれていると思います

于 2012-01-15T12:01:27.097 に答える
4

私は、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.

それはまだ長くて醜いですが、私の意見では、何が/どこに問題があるかがより明確になっています。

于 2012-01-16T00:28:26.080 に答える