2

以下作品MSVC2008和MSVC2010 剛剛罰款C++內聯函數調用函數可以在頭文件後面聲明嗎?

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

是的,這是有點奇怪:FuncA()電話FuncB(),即使(在這一點上)FuncB()是還未宣佈。但是,MSVC2008和MSVC2010認爲這很好。

顯然,gcc並不認爲這很好 - FuncB was not declared in this scope

ISSUE:我有一堆這些,這將是一個「痛苦」來宣佈它們,並在以後定義它們。而且,很難對它們進行「排序」,因此每個函數在聲明之後都只會調用函數。 但是,我猜我需要首先聲明 - 然後定義 - 以後?

對於這些函數是模板還是模板或者在模板類中定義的規則是否不同?

具體來說,我注意到微軟非常「後期編譯」,它接受大量的內部耦合代碼,並且LATER解析(在編譯時,當模板參數化被觸發時),而gcc似乎想要編譯現在當它「看到」的代碼(一個正確的初始過程,並再次在參數化/調用)。

(這個問題表現爲我們端口我們微軟的源代碼的Linux/GCC)

=== UPDATE ===

以下是 「備用」 的情況,我們有(以這個代碼移植工作),並且你的答案會基於這些變化而變化嗎?

// 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定義了通過這些funcs中通過內部enum(我不認爲這個問題)
  • 這些功能的「擴張」,通過一個宏(我認爲顯著 - 見以下)
  • 有這些功能的56(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()不是該類的成員(但它是)。

這是我認爲正在發生的事情:

  • 似乎有是有很多-的代碼(56個功能),這些身體上的「一行」的問題。如果我將這些函數從宏中刪除,則如果我刪除\轉義行結束,則gcc編譯正常。

因此,我認爲(代碼移植)的回答是:

  • 不要使用預處理宏
  • 使從FooParent派生的FooParentBase<>模板類,從我們所衍生Foo ,這就要求typename Foo::enum作爲模板參數

我沒事這些變化(我不喜歡宏),但我覺得很奇怪的是gcc在這裏似乎有問題。

有沒有其他建議如何解決這個問題? (上面是重新考慮你會做什麼?)

+0

你的問題提到模板,但代碼沒有任何。也許你需要第二個代碼示例? –

+0

@Ben,感謝,用'template <>'示例更新了問題,但我現在不認爲模板是問題的一部分(請參閱「UPDATE + 2」) – charley

回答

1

你的代碼對我來說看起來完全合法。類定義中的內聯定義應該被視爲等同於緊跟在類定義之後的內聯定義的聲明(此時FuncB()的聲明將可用)。

我的GCC版本接受此代碼爲有效(當然,假設我提供了每個FuncB()的簡單實現,所有這三個示例都是有效的)。

~$ 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); }

+0

亞當 - 非常感謝這個:問題是一個「行結束」問題(這是一個代碼移植項目,不知道如何通過)。感謝給我一個數據點,我們的實施應該工作。 – charley

2

你所有的三種情況都是正確的,並用g ++和clang編譯。

+0

+1我只是在輸入相同的東西。 .. –

+0

爲什麼FuncB(some_type)在方案B中不起作用?不需要參數類型不需要模板參數列表? –

+0

@ AdamH.Peterson你是對的。我跑了一些更多的測試。 –