سؤال

أرغب في اشتقاق StringStream حتى أتمكن من استخدام المشغل << لإنشاء رسالة سيتم طرحها بعد ذلك. سوف تبدو واجهة برمجة التطبيقات:

error("some text") << " more text " << 42 << std::endl;

هذا يجب أن يفعل

throw "some text more text 42"

لذا فإن ما فعلته هو جعل errorbuf (وراثة من Streambuf) التي تزيد من تحميل طريقة "الفائض" ثم إنشاء ostream (& errorbuf). أتساءل ما إذا كان لا ينبغي لي أن أرث بدلاً من ذلك من Basic_oStringStream أو شيء من هذا القبيل ...

هل كانت مفيدة؟

المحلول

سوف أخرج الماكرو المفضل لدي مرة أخرى هنا:

#define ATHROW( msg )                                               \
{                                                                   \
    std::ostringstream os;                                          \
    os << msg;                                                      \
    throw ALib::Exception( os.str(), __LINE__, __FILE__ );          \
}                                                                   \

في الاستخدام:

ATHROW( "Invalid value: " << x << " should be " << 42 );

نوع الاستثناء هو من مكتبتي الخاصة ، لكنني أعتقد أنك تحصل على الفكرة. هذا أبسط بكثير من استخلاص فئة الدفق الخاصة بك ، ويتجنب الكثير من المضاعفات السيئة مع OP << ().

نصائح أخرى

ربما يمكنك أن تجعل الأمر أسهل من خلال القيام بشيء مثل:

class error_builder
{
public:
    error_builder(const std::string& pMsg = "")
    {
        mMsg << pMsg;
    }

    ~error_builder(void)
    {
        throw std::runtime_error(mMsg.str());
    }

    template <typename T>
    error_builder& operator<<(const T& pX)
    {
        mMsg << pX;

        return *this;
    }

private:
    std::stringstream mMsg;    
};


error_builder("some text") << " more text " << 42 << std::endl;

لاحظ أنه لا ينبغي عليك رمي سلاسل مثلك ، ومن ثم استخدمت std::runtime_error. يجب أن تستمد جميع الاستثناءات من std::exception, ، أيّ runtime_error هل ، وبهذه الطريقة يمكن اكتشاف كل الاستثناءات ذات المغزى مع const std::exception&.

هذا يعمل لأن الحياة المؤقتة حتى نهاية التعبير الكامل.

بعض المشغلين مفقودين من حل GMAN.

class error {
   public:
   explicit error(const std::string& m = "") :
          msg(m, std::ios_base::out | std::ios_base::ate)
   {}

   ~error() {
      if(!std::uncaught_exception()) {
         throw std::runtime_error(msg.str());
      }
   }

   template<typename T>
   error& operator<<(const T& t) {
      msg << t;
      return *this;
   }

   error& operator<<(std::ostream& (*t)(std::ostream&)) {
      msg << t;
      return *this;
   }
   error& operator<<(std::ios& (*t)(std::ios&)) {
      msg << t;
      return *this;
   }
   error& operator<<(std::ios_base& (*t)(std::ios_base&)) {
      msg << t;
      return *this;
   }
   private:
   std::ostringstream msg;
};

عادةً ما أقوم بإنشاء فصول الاستثناء الخاصة بي. عليك فقط تجاوز what() ويمكن أن توفر أكبر عدد من البنائين كما تريد. لإنشاء رسالة الخطأ ، ما عليك سوى استخدام vasprintf (إن وجدت) أو std :: ostringstream كما هو مذكور أعلاه.

هذا مثال:

class CustomException : public std::exception {
private:
    const std::string message;
public:
    CustomException(const std::string &format, ...) {
        va_list args;
        va_start(args, format);
        char *formatted = 0;
        int len = vasprintf(&formatted, format.c_str(), args);
        if (len != -1) {
            message = std::string(formatted);
            free(formatted);
        } else {
            message = format;
        }
        va_end(args);
    }
    const char *what() const {
        return message.c_str();
    }
};

إذا لم يكن لديك vasprintf ، فيمكنك أيضًا استخدام VSNPRINTF مع مخزن مؤقت على المكدس ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top