0

我正在尝试编写带有参数的流操纵器。我有 3 个 int 的 CDate(年、月、日)的课程。所以我需要制作 manipulator 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

我想我需要用那个

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;
}

但我不知道怎么做。

4

4 回答 4

2

您可以pword为此使用数组。C++ 中的每个 iostream 都有两个与之关联的数组。

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

您可以将自己的数据存储在其中。要获得索引,它指的是 alliwordpword数组中的一个空元素,您应该使用 function std::ios_base::xalloc()。它返回 int,您可以将其用作*word. 您应该在启动时获取一次该索引,然后将其用于所有操作*word

然后编写自己的 manip 将如下所示:

操纵器函数,它接收对ios_base对象的引用和指向格式字符串的指针,只是将该指针存储在pword

iosObject.pword(index_from_xalloc) = formatString

然后重载的 operator <<( >>) 以同样的方式从 iostream 对象中获取格式字符串。之后,您只需参考格式进行转换。

于 2015-03-30T16:57:04.450 回答
1

带参数的操纵器与不带参数的操纵器不同!这些只是具有合适输出运算符的类,而不是输出值来操纵流的状态。要操作流状态,您可能需要设置一个合适的值,该值存储在与 dtream 关​​联的 aniword()或 apword()中,并由输出运算符使用。

于 2015-03-30T01:28:27.513 回答
1

正如克里斯建议的那样,我想说你应该只使用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您可能希望将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;

编辑:

再次查看您的问题后,我认为您对插入运算符的工作方式有误解,您不能同时传入对象和格式: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;
于 2015-03-30T01:51:54.100 回答
1

就像 Dietmar 说的那样,您可以将参数推送到 iword() 中,但我发现这种解决方案既乏味又烦人。

我更喜欢将 lambda 函数安装为 iomanips 并使用它们直接调用各种类方法或以其他方式构建自定义打印。为此,我为 mainpulators 创建了一个简单的 100 行模板安装程序/帮助程序类,它可以添加一个 lambda 函数作为任何类的操纵器。

因此,对于您的 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;
}

然后只需指示 << op 使用 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(...) 函数来完成它,但为此您必须访问博客..

于 2015-04-15T13:53:04.960 回答