2014-01-20 3 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::ostreamstd::stringbuf에 사용되는 곳 std::ostream 여전히 std::stringbuf 경우 정상적인 상속 전에 구성되도록 할 것 virtual 기본 클래스 (std::ios)가 있는지 밝혀졌습니다. virtual 상속을 사용하고 std::stringbuf을 첫 번째 기본 클래스로 지정하면 실제로 처음으로 구성됩니다.

+0

개인용 가상'std :: stringbuf'를 파생시키는 이유를 분명히 해 줄 수 있습니까? – Gasim

+0

이것은 멋진 소형 솔루션이지만 어떻게 컴파일합니까? 나는 g ++ 4.8로 노력 중이며 많은 오류가 있습니다. – Bogatyr

+0

@Bogatyr : 우선, 지원되는 rvalue 참조를 얻으려면 C++ 11이 활성화 된 상태 ('-std = C++ 11')로 컴파일해야합니다. 또한 스트림의 구조 이동을 적절하게 지원하는 표준 라이브러리가 있어야합니다. 이것들과 함께, 코드는 그대로 컴파일됩니다. 'libstdC++'가'g ++'4.8을 가지고 배송되면 제대로 구현되었는지 모르겠습니다. 스트림의 이동이 올바르게 지원되지 않는다면'std :: stringbuf'를'std :: unique_ptr '에 집어 넣고 포인터를'std :: stringbuf' 대신에 움직여야 할 수도 있습니다. . –

관련 문제