VisualStudioでC++のコードを書いている時に、"定義へ移動"が動作しない場合の対処法


未だにWindowsでデスクトップアプリなんて作ってる自分が、長年苦しめられていた
特定のcppファイルで"定義へ移動"が動作しなくなる問題の対処法が分かった話

忙しい人のために

ソースと同じフォルダ内に"cpp.hint"というファイルを作成し、

 #define BEGIN_MSG_MAP_EX(theClass) @<
 #define END_MSG_MAP() @>

と、書き込んでください

経緯

自分はよく、WTLというライブラリを使用してデスクトップアプリを書いているのだが、
作成するウィンドウ一つに付き大体

class CScrollConteinerView : 
    public CScrollWindowImpl<CScrollConteinerView>
{
public:
    CScrollConteinerView();

    BEGIN_MSG_MAP_EX(CScrollConteinerView)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
    END_MSG_MAP()

    int OnCreate(LPCREATESTRUCT lpCreateStruct);
    void OnDestroy();

};

こんな感じのクラスを作っていた
しかし、.cpp側に OnCreate などの定義を書いているにも関わらず、OnCreate上で"定義へ移動"を実行したり、逆に定義側で"宣言へ移動"を実行してもうんともすんとも言わずに、OnCreateに波線が引かれ「OnCreate の関数定義が見つかりません。」と言われてしまう…
コンパイルは通るのでC++的に問題のないソースには違いないが、定義へ移動が使えないと不便で仕方がなかった

そんなとき、BEGIN_MSG_MAP_EXにクイックアクションの表示が出ているのに気づいた

ヒントファイルってなんだ?と思い、説明を見るで飛ばされた先のドキュメントを読むと定義へ移動が動作しない原因が判明した
https://docs.microsoft.com/ja-jp/cpp/build/reference/hint-files?view=vs-2019

C++ 参照データベース パーサーは、短時間で大量のコードを解析できるあいまいなパーサーです。 高速な理由の 1 つにコンテンツのブロックをスキップすることが挙げられます。 たとえば、関数の場所とパラメーターのみが記録され、そのコンテンツは無視されます。 一部のマクロはブロックの開始と終了の決定に使用するヒューリスティックの問題を引き起こす可能性があります。 この問題によって、コードの領域が正しく記録されなくなります。

問題を起こす一部のマクロをばっちり使っちゃってました…

WTLはメッセージマップという仕組みを用いて、各種ウィンドウメッセージの処理をメンバ関数に紐づけています
この仕組みのためのマクロを C++ 参照データベース パーサーが理解できず、定義に飛べなかったというわけです

原因が分かれば対処できます
エラーを回避するために、パーサーに問題のマクロ部分をスキップさせるためのヒントファイルを作成します
ヒントファイルの書式はドキュメントに書いてあったのでチャチャっと書いて"ソリューションの再スキャン"を実行
無事波線も消え、定義に飛ぶことができるようになりました!

終わり

たった2行書き込まれたファイルがないために、長年苦労してた自分は一体何だったのだろうか

今度から問題が起きた場合は、プロジェクトの右クリックメニューから"参照データーベース エラーを表示"を実行すれば問題が把握できるので積極的に活用していきたい