2014-01-20 47 views
2

我在努力實現什麼?如何找出輸出流鏈是否結束?

如何才能找到流鏈是否結束?看看下面的功能(所有這些功能都是LogRouter類中在這個問題):

template<typename First, typename... Rest> 
void log(const LogLevel &level_, First first_, Rest... rest_) { 
    sstream << first_ << " "; 
    log(level_, rest_...); 
} 

void log(const LogLevel &level_) { 
    for(auto &route : routes) 
     route->stream() << sstream.str() << std::endl; 

    sstream.clear(); 
    sstream.str(""); 
} 

我想實現在上面,但使用流完全相同的功能。所以,當我到達流的末尾,它需要的最終數據發送到路線和,而不是使用

router.log(LogLevel::Alert, "test stream", 15); 

我希望能夠使用

router.log(LogLevel::Alert) << "test stream " << 15; 

我曾嘗試:

  • std::ostream運算符重載不接受打包的變量。

  • 逐一通過每一個傳遞的值。如下圖所示:

    struct LogEnd {}; 
    
    static LogEnd end() { return LogEnd; } 
    
    template<typename T> LogRouter &operator<<(const T &value) { 
        sstream << value; 
        return *this; 
    } 
    
    LogRouter &log(const LogLevel &level_) { 
        currentLogLevel = level_; //had to add another variable 
        return *this; 
    } 
    
    void operator<<(const LogEnd &end) { 
        for(auto &route : routes) 
         route.stream() << sstream.str() << std::endl; 
        currentLogLevel = LogLevel::None; 
    } 
    

    這給了我什麼,我想語法明智的,但我需要調用額外的LogRouter::end()在每個月底:

    router.log(LogLevel::Alert) << "test stream " << 15 << LogRouter::end(); 
    

    我有一個語法std::endl還,但它會最好的,如果我可以在最後沒有任何東西的情況下調用它

問題

有沒有知道流鏈末端的一種方式。類似於使用遞歸可變參數模板函數時可以執行的操作。

回答

6

您可以將有趣的邏輯放入流的析構函數中。很顯然,我還要妥善處理流,而不是做飯了一些東西,有些看起來像一個流,但不是一個真正的流:

#include <iostream> 
#include <sstream> 
#include <string> 

class logstream 
    : private virtual std::stringbuf 
    , public std::ostream { 
    std::string level; 
public: 
    logstream(std::string l) 
     : std::ostream(this) 
     , level(l) { 
    } 
    logstream(logstream&& other) 
    : std::stringbuf(std::move(other)) 
    , std::ostream(std::move(other)) 
    , level(std::move(other.level)) { 
     this->rdbuf(0); 
    } 
    ~logstream() { 
     std::cout << "do something interesting here(" 
        << this->level<< ", " << this->str() << ")\n"; 
    } 
}; 

logstream trace() { 
    return logstream("trace"); 
} 

int main() 
{ 
    trace() << "hello, world"; 
} 

使用的流緩衝區(std::stringbuf在這種情況下,但也有可能是一個自定義流緩衝區)是在std::ostream之前構建的基類。原則上它是一個數據成員,但是數據成員是在基類之後構建的。因此,它改爲private基類。

事實證明,std::ostream具有virtual基類(std::ios),這將導致std::ostream到仍在std::stringbuf如果正常繼承之前被構造,其中用於std::stringbuf。使用virtual繼承並使std::stringbuf第一個基類確保它確實是首先構造的。

+0

你可以請澄清你爲什麼要派生一個私人虛擬'std :: stringbuf' – Gasim

+0

這是一個可愛的,緊湊的解決方案,但你如何編譯它?我正在嘗試使用g ++ 4.8,並且遇到很多錯誤。 – Bogatyr

+0

@Bogatyr:首先,你需要使用C++ 11編譯('-std = C++ 11')來獲得支持的右值引用。您還需要有一個標準庫,可以正確支持流的移動構建。通過這些,代碼按原樣編譯。我不知道用'g ++'4.8發佈'libstdC++'是否正確實現了。如果流的構建沒有得到很好的支持,你可能需要將'std :: stringbuf'粘貼到'std :: unique_ptr '中,並移動指針而不是'std :: stringbuf' 。 –