3

以下は、MSVC2008 および MSVC2010 で問題なく動作します

class Foo {
public:
  static void FuncA(void) {
    FuncB(); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008
  }
  static void FuncB(void);
};

はい、これはちょっと奇妙です: (その時点で)はまだ宣言されていませんが、 をFuncA()呼び出します。ただし、MSVC2008 と MSVC2010 はこれで問題ないと考えています。FuncB()FuncB()

どうやら、gccこれでいいとは思えない―― FuncB was not declared in this scope

問題: 私はこれらをたくさん持っていますが、それらを宣言して後で定義するのは「苦痛」です。さらに、それらを適切に「順序付け」するのは難しいため、それぞれが宣言された後にのみ関数を呼び出します。 しかし、最初に宣言してから定義する必要があると思いますか?

これらの関数がテンプレートであるかどうか、またはテンプレート クラス内で定義されているかどうかでルールが異なりますか?

gcc具体的には、Microsoft が大量の相互結合コードを受け入れる非常に「遅いコンパイル」であることに気付きまし。 「コードを見る」(正確さのための最初のパス、およびパラメータ化/呼び出し中に再び)。

(この問題は、Microsoft コードを Linux/gcc に移植するときに発生します。)

===更新===

以下は、(このコード移植作業で) 私たちが持っている「代替」シナリオであり、これらのいずれかに基づいてあなたの答えは変わりますか?

  // Alternate-Scenario-B
  class Foo2 {
    public:
      template<typename SOME_TYPE>
      static void FuncA(const SOME_TYPE& some_type) {
        FuncB(some_type); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008
      }
      template<typename SOME_TYPE>
      static void FuncB(const SOME_TYPE& some_type);
    };

...と:

  // Alternate-Scenario-C
  template<typename SOME_TYPE>
  class Foo3 {
    public:
      static void FuncA(const SOME_TYPE& some_type) {
        FuncB(some_type); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008
      }
      static void FuncB(const SOME_TYPE& some_type);
    };

===UPDATE+2===

コンセンサスはこれが有効なC++コードであり、機能するはずであるコメントをありがとう(@Adamが示唆したように、関数「定義済みインライン」はクラスの後に定義されているかのように動作し、定義された関数を呼び出すことができるはずですそのインライン定義の後のクラス インターフェイスで)。

詳しくは:

はい、FuncA()インライン実装の最初の例で実際にこのコンパイル エラーが発生しました。

'FuncB' is not a member of 'Foo'

...使用:

gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

(これは MSVC2008/MSVC2010 で機能することを思い出してください)。

私のコード例 (上記) が不十分であることに気付きました (上記の例では、このエラーは表示されませんgcc)。詳細は次のとおりです。

  • Foo基本クラスがあります(それは問題ではないと思います)
  • Fooこれらの機能を通過する内部enumを定義します(これは問題ではないと思います)
  • これらの関数は、マクロを介して「展開」されます(重要だと思います-以下を参照)
  • これらの関数は 56 個あります (重要だと思います -- 以下を参照してください)。

より完全なコード例は次のようになります (これは自慢ではありません)。

#define FOO_FUNCS(CLASS_NAME,CLASS_ENUM) \
  static void FuncA(CLASS_ENUM value_enum) { \
    FuncB(value_enum); /*PROBLEM*/  \
  } \
  static void FuncB(CLASS_ENUM value_enum) { \
    FuncC(value_enum);  \
  } \
  /*...THERE ARE 56 FUNCS IN THIS MACRO, THREE LINES EACH...*/

class Foo : public FooParent {
  public:
    enum FooEnum { FOO_ONE, FOO_TWO };
    FOO_FUNCS(Foo,FooEnum)  // EXPAND THE 56 FUNCS
};

コード の意図:FooParent基本クラスには、(多くの) 派生クラスによって「共有」されることを意図した実装があります。派生クラスは独自のenum値を定義します。これらの値を使用する関数はenum、マクロを介して実装されました (FooParentは ではなくtemplate<>、派生した に依存できないためenum)。

奇妙な行動:

  • FooA(){FooB();}ネストが「数行」だけで「後で」定義された関数を参照する場合、正常にgccコンパイルされます。ただし、まだ宣言されていない関数が のようにずっと後の場合Foo2(){Foo53();}、それはクラスのメンバーではないgccと結論付けFoo53()ます (ただし、メンバーです)。

これが私が起こっていると思うことです:

  • 物理的に「1 行」にある大量のコード (56 個の関数) に問題があるようです。これらの関数をマクロから削除し、エスケープ行末を削除すると、正常にコンパイルされます。\gcc

したがって、(コード移植)答えは次のとおりだと思います。

  • プリプロセッサ マクロを使用しないでください
  • から派生したFooParentBase<>テンプレート クラスを作成しFooParent、そこから を派生させます。これには、テンプレート パラメータとしてFooが必要です。typename Foo::enum

私はこれらの変更に問題はありません (私はマクロが好きではありませんでした) が、gccここに問題があるように見えるのは奇妙だと思います。

これを修正する方法について他の提案はありますか? (上記のリファクタリングはあなたがすることですか?)

4

2 に答える 2

1

あなたのコードは私には完全に合法に見えます。クラス定義内のインライン定義は、クラス定義の直後にインライン定義がある宣言と同等に扱われることになっています (それまでに FuncB() の宣言が使用可能になります)。

私のバージョンの GCC は、このコードを有効なものとして受け入れます (もちろん、各 FuncB() の簡単な実装を提供すると仮定して、投稿した 3 つの例はすべて)。

~$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
...

ここではもっと情報が必要だと思います。おそらく、GCC のバージョンと表示されている特定のエラー メッセージを投稿してください。

========後の更新に返信=======

マクロで70個の関数を使用して最新の例を試しましたが、gcc 4.6.3でも機能しています。これが私が試したテストです(マクロは明らかな方法で短縮されています):

#include <iostream>
using std::cout;
struct FooParent {
    static void Func71( int ) {
        cout << "Called\n";
    }
};

#define FOO_FUNCS(CLASS_NAME,CLASS_ENUM) \ static void Func1(CLASS_ENUM value_enum) { \ Func2(value_enum); /PROBLEM/ \ } \ static void Func2(CLASS_ENUM value_enum) { \ Func3(value_enum); \ } \ /* Functions Func3...Func69 snipped */ \ static void Func70(CLASS_ENUM value_enum) { \ Func71(value_enum); \ } \ /...THERE ARE 70 FUNCS IN THIS MACRO, THREE LINES EACH.../

class Foo : public FooParent { public: enum FooEnum { FOO_ONE, FOO_TWO }; FOO_FUNCS(Foo,FooEnum) // EXPAND THE 70 FUNCS };

int main() { Foo::Func1(Foo::FOO_ONE); }

于 2013-04-01T19:07:40.820 に答える