簡體   English   中英

需要一個宏從std :: ostringstream和<< arg列表創建std :: string

[英]Need a macro to create a std::string from a std::ostringstream and a << arg list

我想編寫一個宏,該宏將std :: ostream&operator <<串聯對象的列表作為唯一參數,並將合並后的字符串作為單個std :: string對象傳遞給函數。 將合並的字符串傳遞給函數的能力是關鍵。 在下面的示例中,我知道只需將宏定義為ERR_MSG(inputs) std::cout << "ERROR: " << inputs ,即可將示例本身重寫為工作,但是將輸出發送至std :: cout是不是目標,這只是我為示例選擇的測試目標。

我正在使用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傳遞給函數,而不管“輸入”是什么。 對不起,您之前沒有提到。

您當前的問題是,所有各種operator<<函數都返回一個ostream& ,而不是ostringstream& 您可以使用簡單的演員表解決此問題:

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

需要flush是因為std::ostringstream()是臨時的。 因此,您不能在其上調用帶有左值引用的函數(即: std::ostream& )。 像大多數operator<<變體一樣的函數。 flush調用所做的只是將this指針作為左值引用返回。

如果您願意使用某些GCC擴展名 ,您可以在一個宏塊中聲明一個實際的ostringstream,以便可以使用.str()方法而無需進行強制轉換:

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

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

使用do { } while (false)慣用語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);
#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";
}

我不會創建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直接支持的一種類型,它沒有任何作用,但返回std::ostream& ,例如:

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

恢復Nicol的答案是迄今為止最好的答案:

您當前的問題是,所有各種operator<<函數都返回一個ostream& ,而不是ostringstream& 您可以使用簡單的演員表解決此問題:

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

當然,這仍然有一個問題(就像這里的所有答案一樣)

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

會以一種奇怪而混亂的方式行事。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM