1

对于我正在开发的 API,我希望允许用户将自定义对象插入到ostream. (想想内存有限的嵌入式系统中的数千万个 16 位/32 位/48 位对象。)

假设用户初始化底层上下文,并查找以下对象之一:

DDB ddb("xc5vlx330t");
Tilewire tw = ddb.lookUpTilewire("DSP_X34Y0", "DSP_IMUX_B5_3");
...
std::cout << complexDataStructure;

在一个完全不同的范围内,可能嵌套在远离用户显式代码的地方,我们可能需要将对象插入到一个不可用ostream的对象中。ddb

os << tw;

tw 封装的实际值是97,594,974,但期望的输出是这样的:

DSP_IMUX_B5_3@[263,84] DSP "DSP_X34Y0" (1488@77406)

为了使其工作,适当的插入运算符需要访问ddb,但它不能依赖静态或全局变量或函数(出于多线程原因)。我想做是允许用户请求和使用这样的流包装器:

ostream& wrappedCout = ddb.getWrappedOstream(std::cout);

返回的 ostream 子类将包括对 ddb 的引用,供需要它的特殊流插入器使用,以及对原始流的引用——std::cout在这种情况下——它将转发其所有输出。

不幸的是,我提出的继承或组合方案编写起来很混乱(不是一个大问题),并且可能给用户带来问题(一个更大的问题)。关于如何优雅地使 ddb 可用于插入操作员的任何建议?我对 boost.Iostreams 知之甚少,但不确定它是否会对我有所帮助。

4

4 回答 4

1

编写一个自定义流操纵器,使用 iword/pword 机制存储对 ddb 的引用。这是一个示例,您需要在多线程程序中围绕 iwork_indexes 映射添加锁定。

class dbb
{
public:
    explicit dbb(int value) : m_value(value) {}
    int value() const { return m_value; }
private:
    int m_value;
};

class dbb_reliant_type
{
public:
    dbb_reliant_type(const std::string& value) : m_value(value) {}
    const std::string& value() const { return m_value; }
private:
    std::string m_value;
};

typedef std::map<std::ostream*, int> iword_map;
iword_map iword_indexes;

inline int get_iword_index(std::ostream& os)
{
    iword_map::const_iterator index = iword_indexes.find(&os);

    if(index == iword_indexes.end())
    {
        std::pair<iword_map::iterator, bool> inserted = iword_indexes.insert(std::make_pair(&os, os.xalloc()));
        index = inserted.first;
    }

    return index->second;
}


inline std::ostream& operator<<(std::ostream& os, const dbb& value)
{
    const int index = get_iword_index(os);

    if(os.pword(index) == 0)
        os.pword(index) = &const_cast<dbb&>(value);

    return os;
}

std::ostream& operator<<(std::ostream& os, const dbb_reliant_type& value)
{
    const int index = get_iword_index(os);
    dbb* deebeebee = reinterpret_cast<dbb*>(os.pword(index));
    os << value.value() << "(" << deebeebee->value() << ")";
    return os;
}

int main(int, char**)
{
    dbb deebeebee(5);
    dbb_reliant_type variable("blah");
    std::cout << deebeebee << variable << std::endl;
    return 0;
}
于 2010-06-24T23:00:57.523 回答
1

我不完全确定我是否了解什么可以在什么时间访问以及什么可以改变和不能改变,但是....你能做这样的事情吗

struct TilewireFormatter {
    DDB *ddb;
    TilewireFormatter(DDB* d) : ddb(d) {}

    print(std::ostream& out, const Tilewire& obj) {
        // some formatting dependent on ddb
        out << obj;
    }
};

并替换out << tw;formatter.print(out, tw);

然后不为 Tilewire 提供任何类型的 << 运算符重载并传递一个 TilewireFormatter 实例,用于根据 ddb 是什么来格式化它们?

于 2010-06-24T23:02:08.660 回答
0

与其在使用插入运算符时四处寻找并试图找到一种传递上下文信息的方法,我建议您制作类似 choobablue 建议的 print 方法。这是一个不错且简单的解决方案,任何更花哨的东西都可能比它的价值更麻烦。

我也觉得你为嵌入式系统选择 iostreams 很奇怪。它们是 C++ 标准库中最臃肿的部分之一(不仅仅是实现,而是设计),如果您正在使用嵌入式系统,您也可以推出自己的替代方案(仍然基于iostreams 的基本设计),并且可能与尝试跨多个线程有效地使用 iostream 一样快。

于 2010-06-24T23:14:55.763 回答
0

我是这方面的新手,所以如果提供我自己的答案妨碍我与 Gary 分享功劳,那么,Gary 指出了我刚刚通过相同的参考资料偶然发现的内容: 私人使用的流存储: iword、pword 和 xalloc

#include <iostream>

// statically request a storage spot that can be associated with any stream
const int iosDdbIndex = std::ios_base::xalloc();

class DDB {
public:
    // give the stream a pointer to ourselves
    void bless(std::ostream& os) { os.pword(iosDdbIndex) = this; }
    // provide a function that the insertion operator can access
    int getSomething(void) { return 50; }
};

class Tilewire {
    friend std::ostream& operator<< (std::ostream& os, Tilewire tilewire);
    // encapsulate a dummy value
    int m;
public:
    // construct the Tilewire
    Tilewire(int m) : m(m) {}
};

std::ostream& operator<< (std::ostream& os, Tilewire tilewire) {
    // look up the pointer to the DDB object
    DDB* ddbPtr = (DDB*) os.pword(iosDdbIndex);
    // insert normally, and prove that we can access the DDB object's methods
    return os << "Tilewire(" << tilewire.m << ") with DDB param " << ddbPtr->getSomething();
}

int main (int argc, char * const argv[]) {
    DDB ddb;
    ddb.bless(std::cout);
    std::cout << Tilewire(0) << std::endl;
    return 0;
}
于 2010-06-25T01:17:43.233 回答