Необходимо сделать контекст доступным для операторов вставки C ++ Ostream

StackOverflow https://stackoverflow.com/questions/3114460

Вопрос

Для 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, но не уверен, что это поможет мне здесь.

Это было полезно?

Решение

Напишите пользовательский манипулятор потока, в котором хранится ссылка на DDB, используя механизм IWord/Pword. Вот пример, вам нужно добавить блокировку вокруг карты 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;
}

Другие советы

Я не совсем уверен, понимаю ли я, что можно получить в какое время и что может и не могу измениться, но ... Можете ли вы сделать что -то подобное

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?

Вместо того, чтобы разбираться и пытаться найти способ передать контекстную информацию при использовании оператора вставки, я предлагаю сделать что -то вроде метода печати, как предполагает choobablue. Это хорошее и простое решение, и все, что более причудливое, вероятно, больше проблем, чем стоит.

Я также считаю странным, что вы выбираете iostreams для встроенной системы. Они одна из самых раздутых частей стандартной библиотеки C ++ (не только по внедрению, но и по замыслу), и если вы работаете над встроенной системой, вы можете с такой же Базовый дизайн iostreams) и, вероятно, может сделать это так же быстро, как и попытка использовать iostream эффективно и по нескольким потокам.

Я новичок в этом, поэтому в случае предоставления моего собственного ответа мешает мне поделиться кредью с Гэри, ну, Гэри указал на то, что я только что наткнулся на минуты до той же ссылки: Stream Storage для частного использования: 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top