Необходимо сделать контекст доступным для операторов вставки C ++ ostream - PullRequest
1 голос
/ 25 июня 2010

Для 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 для использования специальными потоковыми вставками, которые в этом нуждались, и ссылку на исходный поток & mdash; std::cout в этом случае & mdash; куда он будет пересылать весь свой вывод.

К сожалению, схемы наследования или компоновки, которые я придумала, являются грязными для кодирования (не огромной проблемой) и, возможно, проблематичными для пользователя (гораздо большая проблема). Любые предложения о том, как элегантно сделать ddb доступным для операторов вставки? Я немного знаю о повышении. Iostreams, но не уверен, что это поможет мне здесь.

Ответы [ 4 ]

1 голос
/ 25 июня 2010

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

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? </p>

1 голос
/ 25 июня 2010

Напишите пользовательский потоковый манипулятор, который хранит ссылку на 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;
}
0 голосов
/ 25 июня 2010

Я новичок в этом, так что в случае, если предоставление моего собственного ответа мешает мне поделиться кредитом с Гари, ну, Гэри указал на то, что я только что наткнулся на моменты ранее, по той же ссылке: Потоковое хранилище для частного использования: 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;
}
0 голосов
/ 25 июня 2010

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

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

...