以下は、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
ここに問題があるように見えるのは奇妙だと思います。
これを修正する方法について他の提案はありますか? (上記のリファクタリングはあなたがすることですか?)