1. ホーム
  2. c++

[解決済み】無名名前空間内で宣言された関数の定義が見つからない - 解決方法は?(ビジュアルスタジオ2015)

2022-02-12 03:57:49

質問内容

Visual Studioをインストールしました。 2015 で問題がなかったのに、私のコードの一部が 2013 が表示されるエラーが発生しました。 新しい生産性向上機能 ). しかし、コードはまだ正常にコンパイルされています。

ここで簡単な例を挙げてみましょう。

namespace
{
    void test1(); // what once was OK in VS 2013,
    void test2(); // is now marked with squiggles in VS 2015
}

namespace named
{
    void test3(); // OK, no problem
}

void        test1() { /*...*/ }
void      ::test2() { /*...*/ }
void named::test3() { /*...*/ }

int main() { /*...*/ }

これが問題のスクイッグルです。

マウスを移動させると、次のように表示されます。

<ブロッククオート

test1' の関数定義が見つかりません

test2' の関数定義が見つかりません


なぜか、名前のない名前空間の中で宣言された関数だけがスクイグルを引き起こすことが判明しました。

どのように解決するのですか?

どのように解決するのですか?

緑色のスクイッグは、エラーがあることを教えてくれるのではなく、新しいリファクタリングツールが何かをする機会があることを教えてくれるのです。(赤い四角はエラーを示します。) この場合、以下の宣言にマッチする定義がないことを知らせているのです。 test2 そのため、IDEは生成するよう提案しています。

これは、Visual Studioが不適合な方法で動作しているかもしれませんが、コードに常に存在したエラーを指摘するために起こります。

では、どうなるのでしょうか?問題は、無名名前空間での宣言が、後でグローバル名前空間で定義するのと同じ関数を宣言していないことです。リファクタリングツールはこのことを認識し、宣言された関数の定義を生成するよう提案します。

しかし、マイクロソフトのコンパイラが2つの厳密には不正なコードを受け入れるため、全体としてはまだコンパイル可能です。まず、関数の最初の宣言で名前空間接頭辞を使うことは許されない。のコードは main で、その関数を呼び出すと思われます。Alex Mが彼の解答で示したように、GCCはこれを受け入れないでしょう。Microsoftのコンパイラはこれを受け入れ、名前のない名前空間の宣言と一致する定義として扱います(IDEのツール、インテリセンスとリファクトリは、実際のコンパイラが使うパーサではなく、より準拠したEDGフロントエンドを使ったことを覚えておいてください、これはリファクトリは宣言に定義がないと言うことができ、コンパイラは宣言と一致する定義を扱います)、あるいは名前空間バージョンよりグローバルバージョンを好むだけです。

ところで、この2つのケースを区別するのは簡単だ。コードを書き換えて、次のようにする。 main が関数定義の前に来ます。これはGCCでのあいまいさを解決します。なぜなら、名前空間のある関数だけが宣言されているからです(定義されていないのでリンカエラーになるはずです)。また、Microsoftコンパイラがグローバルバージョンを優先する場合、リンカエラーになりますが、宣言と定義が一致するものとして扱えば、まだコンパイル可能です。

名前なしの名前空間で宣言された関数を定義する場合、関数を外部で定義しようとするのではなく、名前空間を開き直せばよいのです。