سؤال

بالنسبة إلى واجهة برمجة التطبيقات التي أعمل عليها ، أريد السماح للمستخدم بإدخال كائنات مخصصة في 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 باستخدام آلية IWWOR/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 بشكل فعال وعبر خيوط متعددة.

أنا جديد في هذا ، لذلك في حالة توفير إجابتي الخاصة في طريقي لتقاسم الائتمان مع Gary ، أشار غاري إلى ما تعثرت عليه للتو لحظات من خلال نفس المرجع: تخزين الدفق للاستخدام الخاص: IWWORD ، 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