2010-03-17 9 views
2

첫 번째로, 최근 작업 한 대부분은 Java였습니다. 따라서 C++을 "알고"있다고하더라도 C++로 Java를 작성하고 싶지는 않습니다.C++ 스트림 연산자 << 및 조작자/포맷터

그리고 C++ 템플릿은 자바로 돌아갈 때 정말로 놓칠 것입니다.

이제 새로운 형식의 스트림 포매터 (pic)를 만들고 싶다면 생성자에 단일 std :: string 매개 변수가 생깁니다. 출력은

Date is 2010/03/17

가 어떻게이 그림 클래스를 작성 할 수 있어야

cout << pic("Date is 20../../..") << "100317" << endl; 

:

나는 사용자가 같은 것을 쓸 수 있도록하고 싶습니다? 컴파일러는 컴파일러가 수행하는 기본 단계가 무엇인지 확인합니다.

편집 그것으로 그 코드를 변경하는 것이 더 C++ 될 것이다 : 독립 기능 (아마도 템플릿)으로 그림 함수를 작성하는 것이 더 쉬울 수 가능성이

cout << pic("Date is 20../../..", "100317") << endl; 

그리고?

+1

중복 : http://stackoverflow.com/questions/535444/custom-manipulator-for-c-iostream –

+0

고마워요! 그게 내가 원하는거야. – Ayman

+0

위의 코멘트는 실제로 프록시를 만들 수 있음을 증명하는 내 대답을 삭제했습니다. –

답변

2

다른 형식의 printf()를 작성하는 것처럼 들립니다. 이것이 좋은 생각인지는 모르겠지만, 그렇게하기로 결정했다면, 조작자 문제 (형식 문자열을 사용하여 형식화와 관련이없는)가 사라지기 때문에 확실히 자유 함수로 작성해야합니다. 나는 또한 시작하는 템플릿을 피하고, 단순히 문자열 버전 설계하고 작성합니다 같은 함수를 작성하기 전에

void pic(ostream & os, const string & fmt, const string & val); 

을, 당신은 그것의 의미가 무엇인지 당신의 마음에서 아주 명확해야 할 것이다, 나는 '돈되는 너는 아직 믿는다.

+0

자유 형식 기능을 좋아하고 실제로 내 게시물을 편집했습니다. 통화의 의미는 아직 명확하지 않습니다. 그러나 나는 그것이 제안했던 것처럼 행할 수 있어야한다고 생각한다? – Ayman

2

boost::format 라이브러리를 살펴보십시오. (당신이 먼저 문자열을 spliting 줄 수있는 경우)이 같은

일도 2 개 질문이 여기에 있습니다

#include <iostream> 
#include <string> 
#include <boost/format.hpp> 

int main() 
{ 
    const char* a = "102030"; 
    std::string year(a, a + 2); 
    std::string month(a + 2, a +4); 
    std::string day(a + 4); 

    std::cout << boost::format("Date is 20%1%/%2%/%3%")% year % month % day << std::endl; 

} 
+0

제 컴파일러 (비표준 및 레거시 시스템)로 부스트에 약간의 문제가있었습니다. – Ayman

0

작동합니다.

스트림 조작기를 다루는 사람은 따옴표를 따르십시오.

다른 하나는 서식 문제를 다룹니다.

서식을 구문 분석하고 실제 서식을 지정하기 위해 호출되는 AST 표현을 생성 할 수 있으므로 서식을 지정하는 것이 특히 어렵습니다. 구문 분석은 작은 문법 등을 정의해야 함을 의미합니다.

구문 분석/생성을 처리하는 Boost.Spirit와 같은 라이브러리가 있으며 '단순한'Boost.Format보다 훨씬 복잡합니다. 그다지 간단하지 않다.)

이제 구문 분석을 할 수 있습니까?

class Date 
{ 
public: 
    Date(year_t year, month_t month, day_t day); 

    year_t getYear() const; 
    month_t getMonth() const; 
    day_t getDay() const; 
private: 
    year_t mYear; 
    month_t mMonth; 
    day_t mDay; 
}; 

이 클래스의 장점은 여러 위치 :

  • 구조적 정보 : 하나의 구문을 분석하면
  • 검증 할만큼 읽 루트 밖으로 잘못된 날짜 (? 2010년 2월 29일)
  • 모호성 없음 : 실제로 "100102"는 "2010 년 2 월 1 일"또는 "2010 년 1 월 2 일"입니까? (적어도 한번은 구문 분석되지 않음)

그런 다음 작은 형식 엔진을 생성하여 형식에 대해 동일한 작업을 수행 할 수 있습니다.

template <class T> 
class Formatter 
{ 
public: 
    virtual ~Formatter() {} 
    virtual Formatter* clone() const = 0; 
    virtual std::string evaluate(const T& item) const = 0; 
}; 

template <class T> 
class FormatterConstant: public Formatter 
{ 
public: 
    explicit FormatterConstant(const std::string& s): mValue(s) {} 
    virtual Formatter<T>* clone() const { return new FormatterConstant(*this); } 
    virtual std::string evaluate(const T&) const { return mValue; } 

private: 
    std::string mValue; 
}; 

template <class T> 
class FormatterComposite: public Formatter<T> 
{ 
    typedef std::vector< const Formatter<T>* > formatters_type; 
    typedef typename formatters_type::const_iterator const_iterator; 
public: 
    // Need suitable Copy and Assignment Constructors 
    ~FormatterComposite() 
    { 
    for(const_iterator it = mFormatters.begin(), end = mFormatters.end(); 
     it != end; ++it) delete *it; 
    } 

    virtual Formatter<T>* clone() const { return new FormatterComposite(*this); } 

    virtual std::string evaluate(const T& item) const 
    { 
    std::string result; 
    for(const_iterator it = mFormatters.begin(), end = mFormatters.end(); 
     it != end; ++it) result += (*it)->evaluate(); 
    return result; 
    } 

    void imbue(std::ostream& s) { mStream = &s; } 

    FormatterComposite& operator<<(const std::string& s) 
    { 
    mFormatters.push_back(new FormatterConstant<T>(s); } 
    return *this; 
    } 

    FormatterComposite& operator<<(const Formatter<T>& formatter) 
    { 
    mFormatters.push_back(formatter.clone()); 
    return *this; 
    } 

    std::ostream& operator<<(const T& item) const 
    { 
    return (*mStream) << this->evaluate(item); 
    } 

private: 
    std::ostream* mStream; 
    formatters_type mFormatters; 
}; 

template <class T> 
FormatterComposite& operator<<(std::ostream& s, FormatterComposite& c) 
{ 
    c.imbue(s); 
    return c; 
} 


// Usage 
class DateOfYear: public Formatter<Date> 
{ 
public: 
    Formatter<Date>* clone() const { return new DateOfYear(*this); } 
    std::string evaluate(const Date& d) const { return toString(d.getYear()); } 
}; 

extern const DateOfYear year; 

int main(int argc, char* argv[]) 
{ 
    FormatterComposite<Date> formatter; 
    Date date; 
    std::cout << formatter << "Date is 20" 
      << year << "/" << month << "/" << day << date; 
    return 0; 
} 

여기서는 구문 분석을하지 않습니다. 물론 형식이 하드 코드 된 것을 의미합니다 ...

+0

길이와 노력에 정말 감사드립니다. 그러나 그것은 필요한 것보다 훨씬 더 복잡하고 요구 사항과 일치하지 않습니다. 아마 그렇게 말 했어야 했어. 제가 준 것은 그 예이고, 귀하의 게시물은 그 구체적인 예와 관련이 있습니다. 실제로 필요한 것은 모든 유형 또는 문자열에 대한 단순하고 일반적인 목적의 형식화 프로그램입니다. 필자는 약 10 줄의 코드에 포매터를 썼다. 그것은 내가 필요한 것을 정확하게합니다. 내가 원하고 요구하는 것은 'API'사용자에게 직관적 인 간단한 호출 방법입니다. – Ayman

+0

오, 노력에 대해 걱정하지 마라, 나는 단지 내가 흥미있는 질문에 답한다! 선출 된 솔루션을보고 싶습니다. 코드를 게시 할 수 있습니까? –

0

여기에 내가 한 일에 대한 초기 해결책이 있습니다. 문제는 내가 아직 템플릿화할 수 없다는 것입니다. 만약 그렇다면, 그림 포맷터를 호출하면 pic<float>("$(...)", 2.56)처럼 보이고 코드가 더럽습니다.

#include <iostream> 
#include <string> 

using namespace std; 

class pic { 
private: 
    const string& _v; 
    const string& _pic; 
public: 

    pic(const string& p, const string& v) : _v(v), _pic(p) { 
    } 

    friend ostream & operator<<(ostream& os, const pic& p) { 
     bool done = false; 
     int pi = 0; 
     int vi = 0; 
     while (!done) { 
      os << (p._pic[pi] == '.' ? p._v[vi++] : p._pic[pi]); 
      done = ++pi > p._pic.length() || vi > p._v.length(); 
     } 
     return os; 
    } 
}; 

int main(int argc, char** argv) { 
    cout << "The formatted date is: " << pic("20../../..", "100317") << endl; 
    return 0; 
} 
관련 문제