Pregunta

Para una API que estoy trabajando, quiero para permitir al usuario insertar objetos personalizados en un ostream, pero estos objetos no tienen significado por sí mismos, y también lo son limitaciones de memoria para incluir un puntero adicional o referencia para el contexto . (Piense en decenas de millones de objetos 16- / 32- / 48-bits en un sistema embebido con memoria limitada.)

Supongamos que el usuario inicializa el contexto subyacente, y se ve uno de estos objetos:

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

En un ámbito completamente diferente, posiblemente anidada lejos de código explícito del usuario, es posible que al insertar el objeto en un ostream, con ddb disponible.

os << tw;

El valor real encapsulado por tw es 97,594,974, pero la salida deseada es la siguiente:

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

Para que esto funcione, el operador de inserción apropiada necesitaría acceso a ddb, pero no puede depender de variables o funciones (por razones multithreading) estáticas o globales. Lo que me como a hacer es permitir que el usuario pueda solicitar y usar un tipo envoltura de secuencia de la siguiente manera:

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

La subclase de regresar de ostream incluiría una referencia a DDB para el uso de dispositivos de inserción de flujo especiales que lo necesitaban, y una referencia a la original stream-std::cout en este caso donde se remitiría toda su producción.

Por desgracia, los esquemas de herencia o de composición que he llegado con son un poco incómodo de código de arriba (no una enorme preocupación), y posiblemente problemático para el usuario (una preocupación mucho más grande). ¿Alguna sugerencia sobre cómo hacer elegantemente DDB disposición de los operadores de inserción? Soy consciente de boost.Iostreams marginalmente, pero no estoy seguro que me va a ayudar aquí.

¿Fue útil?

Solución

Escribir un manipulador de flujo personalizado que almacena una referencia a DDB utilizando el iword / pword mecanismo. Este es un ejemplo, que había necesidad de añadir bloqueo alrededor de las iwork_indexes mapa en un programa de multiproceso.

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

Otros consejos

No estoy del todo seguro si entiendo lo que se puede acceder en qué momento y qué se puede y no se puede cambiar, pero .... se puede hacer algo como esto

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

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

y reemplazar out << tw; con formatter.print(out, tw);

a continuación, no proporciona ningún tipo de sobrecarga del operador << para Tilewire y pasar una instancia de TilewireFormatter alrededor que se utiliza para dar formato a ellos en base a lo DDB es?

En lugar de esquivar alrededor y tratando de encontrar una manera de pasar información contextual mientras se utiliza el operador de inserción, le sugiero que haga algo así como un método de impresión como choobablue sugiere. Es un agradable y solución simple y nada más elegante es probablemente más problemas de lo que vale la pena.

También parece extraño que elija iostreams para un sistema embebido. Son una de las partes más hinchados de la biblioteca de C ++ estándar (no sólo por la aplicación, sino por diseño) y si está trabajando en un sistema embebido, usted podría así rodar su propia alternativa de esto (aún en base a la diseño de iostreams básica) y, probablemente, puede hacerlo tan rápido como tratando de utilizar con eficacia iostream ya través de múltiples hilos.

Soy nuevo en esto, por lo que en caso de proporcionar mi propia respuesta se interpone en el camino de mí compartir el crédito con Gary, así, Gary señaló lo que había tropezado con momentos antes a través de la misma referencia: corriente de almacenamiento para uso privado: iword, pword y 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top