2012-09-28 50 views
0

我想寫一個宏,它只需要一個std :: ostream列表& operator < < <級聯對象並將統一字符串作爲單個std :: string對象傳遞給函數。將合併字符串傳遞給函數的能力是關鍵;在下面的示例中,我知道示例本身可以被重寫爲簡單地通過將宏定義爲ERR_MSG(inputs) std::cout << "ERROR: " << inputs來工作,但將輸出發送到std :: cout不是目標,它只是我爲示例選擇的測試目標。需要一個宏來創建一個std :: ostringstream std :: string和一個<< arg list

我正在使用GCC 4.1.2(Red Hat 4.1.2-52)並且升級它不是一個選項。這裏是什麼,我已經嘗試了很熬下來的版本:

#include <sstream> 
#include <iostream> 

#define ERR_MSG(inputs) errMsg(std::ostringstream().str())   // 1 
#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2 
<aReturnType> errMsg(const std::string& msg)         // use with 1 & 2 
{ 
    std::cout << "\nERROR: " << msg << "\n\n"; 
    return <someObjectCreatedBasedOnTheInput>; 
} 

#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs)   // 3 
<aReturnType> errMsg(const std::ostringstream& msg)       // use with 3 
{ 
    std::cout << "\nERROR: " << msg.str() << "\n\n"; 
    return <someObjectCreatedBasedOnTheInput>; 
} 

int main() 
{ 
    ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!"); 
} 

宏#1編譯,但當然版畫不過是「」的消息。無論是宏2 & 3編譯,併產生以下錯誤:

#define ERR_MSG(inputs) errMsg((std::ostringstream()<<inputs).str()) // 2 
error: ‘struct std::basic_ostream<char, std::char_traits<char> >’ has no member named ‘str’ 

#define ERR_MSG(inputs) errMsg(std::ostringstream()<<inputs)   // 3 
no matching function for call to ‘errMsg(std::basic_ostream<char, std::char_traits<char> >&)’ 
    note: candidates are: char* errMsg(const std::string&) 
    note:     char* errMsg(const std::ostringstream&) 

興趣我怎麼能改寫這個沒有宏;我可以很輕鬆地做到這一點。

===更新:=== 我忘了提及,在它的真實使用情況下,宏調用的函數返回一個可能被宏的調用者使用的對象。這使無法在單個表達式中實現的宏實現失效,其結果是宏調用的函數的返回類型。不管「輸入」是什麼,宏的「什麼都不做」實現(對於發佈版本)只會將一個空的std :: string傳遞給該函數。對不起,先不提。

+0

'std :: ostringstream :: operator <<'返回一個'std :: ostream&'。 – chris

+0

嗯。好。關於這個目標如何實現的任何想法? (使用宏和<<創建一個傳遞給函數的std :: string)? – phonetagger

+0

我相信'std :: ostream'中有一個很好的函數,你可以使用const std :: ostream&'overload來打印它。它可能是'rdbuf',但我忘記了。 – chris

回答

3

您目前的問題是,所有各種operator<<函數返回ostream&而不是ostringstream&。您可以解決與a simple cast

#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str()) 

是需要的,因爲flushstd::ostringstream()一個臨時的。因此,您不能調用帶左值引用的函數(即:std::ostream&)。像大多數功能operator<<變種。所有flush調用都將返回this指針作爲左值引用。

+0

該代碼片段打印'「一個數字:」'爲'0x804952824'! –

+1

@j_random_hacker:我解決了這個問題.. –

+0

「...你不能調用需要左值引用的函數... ...所有的'flush'調用都會返回'this'指針作爲左值參考。」嗯。有一天我希望理解這意味着什麼。但是看起來如果這是全部的flush(),那麼同樣的事情應該可以通過某種類型的cast + dereference組合來實現? – phonetagger

1

如果你願意使用一些GCC extension,你可以聲明宏內的實際ostringstream塊中,使名爲.str()方法可以在不鑄件使用:

#define ERR_MSG(inputs) \ 
    do { std::ostringstream _s_; _s_<<inputs;errMsg(_s_.str()); } while(false) 

演示:http://ideone.com/clone/y56lc

+0

只要擺脫那些外面的parens,它將在任何編譯器上工作! :)然後你只是定義一個普通塊。外層作用域是否包含名爲'_s_'的內容並不重要,因爲'_s_'的查找將始終找到最內層聲明的內容(可能會阻止奇怪的Koenig查找邊角的情況); '_s_'對象在關閉時被銷燬並清理乾淨'}'! –

+1

@j_random_hacker注意大小寫:'int _s_ = 7; ERR_MSG(__ __Ş)'。你會得到什麼,而不是'7' ...隱藏外部名稱並不總是一件好事。如果沒有這個gcc擴展,它將不會編譯:'if(true)ERR_MSG(7); else ERR_MSG(6);'。查看我的答案便攜式解決方案。 – PiotrNycz

+0

@j_random_hacker。嗯對。不知何故,我想不必要地將宏保留爲表達式,儘管聲明沒有問題。 – kennytm

0

我不會創建std::ostringstream,而是從std::ostream派生的類的析構函數中調用一個函數。下面是該方法的一個例子:

#include <sstream> 
#include <iostream> 

void someFunction(std::string const& value) 
{ 
    std::cout << "someFunction(" << value << ")\n"; 
} 

void method(std::string const& value) 
{ 
    std::cout << "method(" << value << ")\n"; 
} 

class FunctionStream 
    : private virtual std::stringbuf 
    , public std::ostream 
{ 
public: 
    FunctionStream() 
     : std::ostream(this) 
     , d_function(&method) 
    { 
    } 
    FunctionStream(void (*function)(std::string const&)) 
    : std::ostream(this) 
    , d_function(function) 
    { 
    } 
    ~FunctionStream() 
    { 
     this->d_function(this->str()); 
    } 
private: 
    void (*d_function)(std::string const&); 
}; 

int main(int ac, char* av[]) 
{ 
    FunctionStream() << "Hello, world: " << ac; 
    FunctionStream(&someFunction) << "Goodbye, world: " << ac; 
} 

的例子的使用不使用宏但這可以容易地圍繞上述使用的FunctionStream()包裹。請注意,在宏中,您可能想要確保宏的用戶看到的類型是std::ostream&而不是臨時類型,因此可以直接與用戶定義的輸出運算符一起使用。爲此,你應該有通過std::ostream直接支持的類型不具有任何影響的一個插入,但返回一個std::ostream&,例如:

#define SomeMacro(output) FunctionStream(&someFunction) << "" << output 
+0

我認爲這有點不重要。他不想用字符串調用任何函數;他希望能夠將ERR_MSG用作參數*作爲函數。也可能有其他的功能參數。 –

+0

@NicolBolas:基於他的例子,他_does_希望得到一個'std :: string const'!它的目標似乎是創建宏,它可以用來刪除,例如,基於某些宏定義的調試輸出。 –

+0

我有一種感覺,這是一個很好的答案,但它比羅布/尼科爾/克里斯多德多一點。 – phonetagger

1

使用do { } while (false)成語做了幾行宏。

#define ERR_MSG(inputs) \ 
    do { \ 
     std::ostringstream osERR_MSG; \ 
     osERR_MSG << inputs; \ 
     errMsg(osERR_MSG.str()); \ 
    } while (false) 


int main() { 
    if (1) ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!"); 
    else return 0; 
} 

我做了這樣奇怪的名字osERR_MSG是避免儘可能多的情況下,像這種情況的原因是:

int osERR_MSG = 7; 
ERR_MSG(osERR_MSG); 
+0

再次:你定義了一個名爲'os ___'的變量(三個下劃線),然後調用errMsg(os __。str())'(兩個下劃線)! –

+0

只是錯誤,,, – PiotrNycz

1
#include <sstream> 
#include <iostream> 

#define ERR_MSG(inputs) errMsg(std::ostringstream().flush()<<inputs) 
int errMsg(std::ostream& os) 
{ 
    std::ostringstream& oss(static_cast<std::ostringstream&>(os)); 
    const std::string& str(oss.str()); 
    std::cout << "\nERROR: " << str << "\n\n"; 
    return str.length(); 
} 

int main() 
{ 
    int i = ERR_MSG("A number: " << 24 << ", a char: " << 'c' << ", that's all!"); 
    std::cout << i << "\n"; 
} 
+0

嚴......這似乎工作,但是將os的地址轉換爲std :: ostringstream指針並取消引用它來初始化oss引用變量安全?不僅僅是GCC? – phonetagger

+0

這似乎也工作...'const const std :: string&str((static_cast (os))。str());'....但是這是安全的(與上面相同的問題) ? – phonetagger

+1

爲什麼在<<輸入之前需要使用.flush()沒有它,我會得到奇怪的數字來代替輸出中的「A number:24」,就像我拿到Nicol/ChrisDodd的答案一樣。但有趣的是,如果我將.flush()添加到Nicol/ChrisDodd的回答中,突然間他們的答案也會奏效! – phonetagger

0

復原尼科爾的答案,因爲它迄今最好的:

您目前的問題是所有各種operator<<函數都會返回ostream&,而不是ostringstream&。您可以解決與a simple cast

#define ERR_MSG(inputs) errMsg((static_cast<std::ostringstream&>(std::ostringstream().flush() << inputs)).str()) 

當然,這仍然有問題(像這裏所有的應答)類似

ERR_MSG(x ? "x is true" : "x is false") 

將在奇數和混亂地胡作非爲。

+0

這是一個很好的答案,但*它不起作用*。這就是我刪除它的原因。它將第一個字符串打印爲指針而不是「char *」。 –

+0

請注意我的評論下面羅布的職位。如果在std :: ostringstream()和<<輸入之間添加.flush(),您的答案會起作用。我只是不明白爲什麼.flush()是必要的或它做了什麼。 – phonetagger

+0

@phonetagger:就像我剛剛編輯這個答案的樣子? –

相關問題