2015-03-29 2 views
1

Я пытаюсь написать манипулятор потока с аргументами. У меня есть класс с 3-мя CD CD (Год, Месяц, День). Так что мне нужно сделать манипулятор date_format(const char*). , например. :Пользовательский манипулятор для класса

CDate a(2006, 5, 15); 
cout <<"DATE IS : " << date_format("%Y-hello-%d-world-%m-something-%d%d") << a; 

выход будет:

DATE IS : 2006-hello-15-world-5-something-1515 

Guess мне нужно использовать, что

ios_base & dummy_date_format_manipulator (ios_base & x) 
{ 
    return x; 
} 

ios_base & (* (date_format (const char * fmt)))(ios_base & x) 
{ 
    return dummy_date_format_manipulator; 
} 

, но я не знаю, как.

+2

Что случилось с 'std :: put_time'? – chris

+0

@chris У OP, похоже, уже есть понятие 'put_time', поскольку он использует спецификаторы преобразования в своем заявлении о формате. Я вложил ответ с вашим предложением, но трудно божественно, если это то, что ОП предназначил вообще. –

+1

@ JonathanMee, честно говоря, я думаю, что эти форматы довольно распространены. Довольно уверен, что я быстро проверил некоторую дату PHP («% Y.% m.% D») на днях, и я не могу вспомнить, почему. – chris

ответ

2

Для этого можно использовать массив pword. Каждый iostream в C++ имеет два связанных с ним массива.

ios_base::iword - array of ints 
ios_base::pword - array of void* pointers 

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

Тогда программирование собственный Manip будет выглядеть следующим образом:

функции манипулятором, который получает ссылку на ios_base объект и указатель на строку формата, просто сохраняет этот указатель в pword

iosObject.pword(index_from_xalloc) = formatString 

Тогда перегруженный оператор << (>>) получает строку формата из объекта iostream таким же образом. После этого вы просто сделаете преобразование, ссылающееся на формат.

1

Манипуляторы с аргументами не работают так же, как и без аргументов! Это просто классы с подходящим оператором вывода, который вместо вывода значения управляет состоянием потока. Чтобы управлять состоянием потока, вы, вероятно, настроите значение suitabe, сохраненное с помощью iword() или pword(), связанное с dtream и используемое оператором вывода.

1

Как chris предложил, я бы сказал, что вы должны просто использовать tm, а не свой собственный класс даты:

tm a{0, 0, 0, 15, 5, 2006 - 1900}; 

cout << put_time(&a, "%Y-hello-%d-world-%m-something-%d%d"); 

Если вы должны реализовать приходят пользовательские функции, которые не могут быть выполнены с помощью get_time и put_time тогда вы d, вероятно, хотите использовать tm элемент как часть вашего класса, чтобы вы могли просто расширить функциональные возможности, которые уже есть:

class CDate{ 
    tm m_date; 
public: 
    CDate(int year, int month, int day): m_date{0, 0, 0, day, month, year - 1900}{} 
    const tm& getDate() const{return m_date;} 
}; 

ostream& operator<<(ostream& lhs, const CDate& rhs){ 
    auto date = rhs.getDate(); 
    return lhs << put_time(&a, "%Y-hello-%d-world-%m-something-%d%d"); 
} 

вы могли тогда использовать CDate следующим образом:

CDate a(2006, 5, 15); 

cout << "DATE IS:" << a; 

EDIT:

После снова глядя на ваш вопрос, я думаю, что у вас есть неправильное представление о том, как оператор вставки работает, вы не можете передать как объект и формат: https://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx

Если вы хотите, чтобы указать формат, но по-прежнему сохраняют свой CDate класс, я снова предлагаю использовать put_time:

cout << put_time(&a.getDate(), "%Y-hello-%d-world-%m-something-%d%d"); 

Если вы снова настаиваете на написание собственной функции принимающего формата вам необходимо создать вспомогательный класс, который можно построить инлайн и поддержку, с оператором вставки:

class put_CDate{ 
    const CDate* m_pCDate; 
    const char* m_szFormat; 
public: 
    put_CDate(const CDate* pCDate, const char* szFormat) : m_pCDate(pCDate), m_szFormat(szFormat) {} 
    const CDate* getPCDate() const { return m_pCDate; } 
    const char* getSZFormat() const { return m_szFormat; } 
}; 

ostream& operator<<(ostream& lhs, const put_CDate& rhs){ 
    return lhs << put_time(&rhs.getPCDate()->getDate(), rhs.getSZFormat()); 
} 

Вы могли бы использовать это как следует:

cout << put_CDate(&a, "%Y-hello-%d-world-%m-something-%d%d") << endl; 
0

Как Dietmar сказал, что вы можете нажать Params в iword(), но я найти такого рода решения, чтобы быть утомительным и раздражает ..

Я предпочитаю просто установить лямбда-функции в качестве iomanips и использовать их непосредственно вызывать методы различных классов или иным образом создавать пользовательскую печать на месте. Для этой цели я создал простой шаблон 100 линии установки/вспомогательный класс для mainpulators, который может добавить функцию лямбды как манипулятор любого класса ..

Так для CDate вы можете определить вы Manip в

std::ostream& dummy_date_format_manipulator (std::ostream& os) 
{ 
    CustomManip<CDate>::install(os, 
         [](std::ostream& oos, const CDate& a) 
         { 
          os << a.year() 
           << "-hello-" 
           << a.day() 
           << "-world-" 
           << a.month() 
           << "-something-" 
           << a.day() << a.day(); 
         }); 
    return os; 
} 

Тогда просто направить < < цит использовать помощника Manip монтажники печати:

std::ostream& operator<<(std::ostream& os, const CDate& a) 
{ 
    CustomManip<CDate>::print(os, a); 
    return os; 
} 

И ваш основном делается ..

Код mainp инсталлятор и полностью рабочий пример в моем блоге по адресу: http://code-slim-jim.blogspot.jp/2015/04/creating-iomanip-for-class-easy-way.html

Но чтобы быть хорошо .. здесь ключевая часть вы хотите положить в .h где-то меньше всех распечаток, чтобы продемонстрировать как это работает:

//g++ -g --std=c++11 custom_class_manip.cpp 

#include <iostream> 
#include <ios> 
#include <sstream> 
#include <functional> 

template <typename TYPE> 
class CustomManip 
{ 
private: 
    typedef std::function<void(std::ostream&, const TYPE&)> ManipFunc; 

    struct CustomManipHandle 
    { 
     ManipFunc func_; 
    }; 

    static int handleIndex() 
    { 
     // the id for this Custommaniputors params 
     // in the os_base parameter maps 
     static int index = std::ios_base::xalloc(); 
     return index; 
    } 

public: 
    static void install(std::ostream& os, ManipFunc func) 
    { 
     CustomManipHandle* handle = 
      static_cast<CustomManipHandle*>(os.pword(handleIndex())); 

     // check if its installed on this ostream 
     if (handle == NULL) 
     { 
      // install it 
      handle = new CustomManipHandle(); 
      os.pword(handleIndex()) = handle; 

      // install the callback so we can destroy it 
      os.register_callback (CustomManip<TYPE>::streamEvent,0); 
     } 

     handle->func_ = func; 
    } 

    static void uninstall(std::ios_base& os) 
    { 
     CustomManipHandle* handle = 
      static_cast<CustomManipHandle*>(os.pword(handleIndex())); 

     //delete the installed Custommanipulator handle 
     if (handle != NULL) 
     { 
      os.pword(handleIndex()) = NULL; 
      delete handle; 
     } 
    } 

    static void streamEvent (std::ios::event ev, 
          std::ios_base& os, 
          int id) 
    { 
     switch (ev) 
     { 
      case os.erase_event: 
       uninstall(os); 
       break; 
      case os.copyfmt_event: 
      case os.imbue_event: 
       break; 
     } 
    } 

    static void print(std::ostream& os, const TYPE& data) 
    { 
     CustomManipHandle* handle 
      = static_cast<CustomManipHandle*>(os.pword(handleIndex())); 

     if (handle != NULL) 
     { 
      handle->func_(os, data); 
      return; 
     } 

     data.printDefault(os); 
    } 
}; 

конечно, если вы действительно нужны параметры, то используйте функцию CustomManip :: make_installer (...), чтобы это сделать, но для этого вам придется посетить блог ..