2016-04-17 5 views
2

Я хотел бы перегружать operator<< так:оператор перегрузки <<

ostringstream oss; 
MyDate a(2000, 1, 2); 
oss << dateFormat("%Y/%m/%d") << a; 
assert(oss.str() == "2000-01-02"); 

так, что дата в a будет отформатирован в определенном формате. Как достичь этого?

+1

ли, что 'должен f' быть' a'? –

+0

Да, отредактировано в исходном коде – Stepan

+0

Когда вы начнете и попробуйте написать его самостоятельно. – hgiesel

ответ

3

Чтобы сохранить пользовательское состояние в потоке, вам нужно использовать статическую функцию xalloc, чтобы получить уникальный индекс, а затем либо pword, чтобы получить указатель на этот индекс (выделенный специально для каждого потока, в котором он используется) , или iword, чтобы получить целое число в этом индексе (выделено специально для каждого потока, в котором он используется). В вашем случае вы, вероятно, захотите pword. Вы можете использовать указатель, возвращаемый pword, чтобы указать на динамически выделенный объект, который хранит информацию о форматировании.

struct DateFormatter 
{ 
    // The implementation of this class (e.g. parsing the format string) 
    // is a seperate issue. If you need help with it, you can ask another 
    // question 

    static int xalloc_index; 
}; 

int DateFormatter::xalloc_index = std::ios_base::xalloc(); 

void destroy_date_formatter(std::ios_base::event evt, std::ios_base& io, int idx) 
{ 
    if (evt == std::ios_base::erase_event) { 
     void*& vp = io.pword(DateFormatter::xalloc_index); 
     delete (DateFormatter*)(vp); 
    } 
} 

DateFormatter& get_date_formatter(std::ios_base& io) { 
    void*& vp = io.pword(DateFormatter::xalloc_index); 
    if (!vp) { 
     vp = new DateFormatter; 
     io.register_callback(destroy_date_formatter, 0); 
    } 
    return *static_cast<DateFormatter*>(vp); 
} 

std::ostream& operator<<(std::ostream& os, const DateFormatter& df) { 
    get_date_formatter(os) = df; 
    return os; 
} 

std::ostream& operator<<(std::ostream& os, const MyDate& date) 
{ 
    DateFormatter& df = get_date_formatter(os); 

    // format output according to df 

    return os; 
} 

int main() { 
    MyDate a (2000, 1, 2); 
    std::cout << DateFormatter("%Y/%m/%d") << a; 
} 

Это стандартный метод. Это ужасно, на мой взгляд. Я предпочитаю альтернативный подход, который должен передать объект даты вместе с форматированием как единым объектом. Например:

class DateFormatter 
{ 
    const MyDate* date; 
    std::string format_string; 
    DateFormatter(const MyDate& _date, std::string _format_string) 
     :date(&_date) 
     ,format_string(_format_string) 
    {} 

    friend std::ostream& operator<<(std::ostream& os, const DateFormatter& df) { 
     // handle formatting details here 
     return os; 
    } 
}; 

int main() { 
    MyDate a (2000, 1, 2); 
    std::cout << DateFormatter(a, "%Y/%m/%d"); 
} 
+0

Как и когда DateFormatter удаляется в первом пример? – kfsone

+0

@ksfone: Если вы имеете в виду, когда используется инструкция delete, используемая на нем, никогда. Его срок службы заканчивается программой. –

+0

@kfsone: Знаешь что? Это плохо. Я думал, что будет создан только один из этих объектов, но я понял, что он будет создан для каждого созданного потока (что может быть проблемой с чем-то вроде строковых потоков, которые могут возникать снова и снова). Я не часто это делаю, поэтому я забыл, как это сделать. Я исправлю это. –

0

Или вы можете сделать что-то подобное (с использованием статической переменной):

#include <iostream> 

struct MyDate 
{ 
    MyDate(int y, int m, int d): year{y}, month{m}, day{d} {} 

    int year{}; 
    int month{}; 
    int day{}; 
}; 

class DateFormatter 
{ 
public: 
    DateFormatter(const std::string & format) 
    { 
     format_ = format; 
    } 

    static const std::string & format() 
    { 
     return format_; 
    } 

private: 
    static std::string format_; 
}; 

std::string DateFormatter::format_ = {"Default Format"}; 

std::ostream & operator<< (std::ostream & stream, const DateFormatter &) 
{ 
    return stream; 
} 

std::ostream & operator<< (std::ostream & stream, const MyDate & date) 
{ 
    auto currentFormat = DateFormatter::format(); 
    // some code using current format ... 
    return stream << currentFormat << " - " << date.year << "/" << date.month << "/" << date.day; 
} 

int main(void) 
{ 
    MyDate date{2016,4,18}; 
    std::cout << date << std::endl; 
    std::cout << DateFormatter("New format") << date << std::endl; 

    return 0; 
} 
+0

А что, если кто-то хочет писать в двух разных потоках, используя одновременно два разных формата? –

Смежные вопросы