2011-07-06 117 views
4

我們有一個自定義的Logging類,它在VisualStudio 2010中編譯得很好,但在Linux上用g ++編譯時會拋出錯誤。我們收到錯誤消息如下:g ++「operator <<」聲明爲非函數「

Logger.hpp:84: error: declaration of "operator<<" as non-function 
Logger.hpp:84: error: expected ";" before "(" token 
Logger.hpp:91: error: expected ";" before "inline" 
Logger.hpp:91: error: declaration of "operator<<" as non-function 
Logger.hpp:91: error: expected ";" before "(" token 
Logger.hpp:98: error: expected ";" before "typedef" 

的代碼了各行如下:

/*:84*/inline Logger& operator<<(std::_Smanip<std::ios_base::fmtflags> output) 
{ 
     if (this->loggingEnabled()) 
       std::cout << output; 
     return *this; 
} 

inline Logger& operator<<(std::_Smanip<std::streamsize> output) 
{ 
     if (this->loggingEnabled()) 
       std::cout << output; 
     return *this; 
} 

typedef std::basic_ostream<char, std::char_traits<char> >& (*StdEndl)(std::basic_ostream<char, std::char_traits<char> >&); 
inline Logger& operator<<(StdEndl output) 
{ 
     if (this->loggingEnabled()) 
       std::cout << output; 
     return *this; 
} 

重載<<操作做工精細的其他方法,所以我的猜測是錯誤的有東西與參數類型(std::_Smanip);任何線索爲什麼?

感謝, 本

+1

在這裏做什麼$符號? –

+0

對不起,複製並粘貼錯誤,現在修復。 – Ben

+2

以下劃線後跟大寫字母開頭的名稱保留用於實現特定的細節,因此'std :: _ Smanip'可能是VS特定的。 – hammar

回答

5

_Smanip是Microsoft的擴展,而不是標準庫的一部分。這就是爲什麼你的代碼在Visual C++下編譯的原因。

Here's關於使用_Smaniphere's的另一個關於如何避免使用它並編寫可移植代碼的MSDN文章。

編輯:發現另一個link,它詳細解釋了帶參數的操縱器。他們也討論實現自定義方法的方法。

+0

感謝您的鏈接;我沒有看到第二個應用程序是如何應用的 - 我基本上只是想將任何標準流操縱器(如格式化)傳遞到我的記錄流... – Ben

+1

@Ben:這只是爲了顯示'_Smanip'背後的概念。你不能把內聯Logger&operator <<(std :: _smanip 輸出)改成內聯Logger&operator <<(std :: ios_base :: fmtflags標誌),然後調用'函數內的std :: cout << std :: setf(flags)'?不知道如何解決其他2. – Praetorian

+0

謝謝,這似乎修復它。但在函數中它是'std :: cout.setf(flags)'。 – Ben

4

我覺得這裏的錯誤消息是有點混亂,但問題似乎是_Smanip沒有在GCC的的libstdC++定義(或者至少它不是在我安裝的4.6.0 )。回想一下,在C++中,以_開頭的任何符號和大寫字母,或者兩個__代表實現保留的符號,在這種情況下,看起來是VC擴展。一個與gcc郵件列表相關的帖子,暗示smanip在C++ 98草案中的某一點,但後來被刪除(因此也從GCC的C++運行時中刪除,這往往會嚴格追蹤ISO標準) - http://gcc.gnu.org/ml/gcc-help/2003-10/msg00385.html

您必須修改代碼才能使用不同的GCC技術。看看libstdC++的實現<iomanip>可能會有所幫助。

1

這個錯誤信息真的不是很有幫助。正如其他答案指出的那樣,_Smanip不是標準庫的官方部分,但由於潛在的問題,我偶然發現了這個問題。

由於_Smanip不是已定義的類型,GCC編譯器(甚至在最新版本),似乎解釋運算符重載的定義(未定義類型參數)爲類成員的聲明。我碰巧發現了這一點,因爲在提供派生類過載時忘記了包含基類的模板參數。由於模板參數是類型名稱的一部分,我所指定的參數類型實際上並不是一個定義的類型。

只是想到我會分享這個問題的任何其他人。當然,解決方案是確保在爲運算符超載提供聲明時,您的參數具有完全聲明的類型。

+0

非常有用。如果g ++有錯誤消息,並不需要站在Delphic Oracle前的解釋器,那將會很好。 – DragonLord