Question

Je veux tirer un stringstream pour que je puisse utiliser l'opérateur << pour construire un message qui sera ensuite jeté. L'API ressemblerait à ceci:

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

Cela devrait faire un

throw "some text more text 42"

Alors, ce que je faisais est de faire un errorbuf (héritant de streambuf) qui surchargent la méthode du « débordement », puis créer un ostream (et errorbuf). Je me demande si je ne devrais pas hériter de la place basic_ostringstream ou quelque chose ...

Était-ce utile?

La solution

Je vais trotter mon macro nouveau ici favori:

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

En utilisation:

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

le type d'exception est de ma propre bibliothèque, mais je pense que vous avez l'idée. Ceci est beaucoup plus simple que de dériver votre propre classe de flux, et évite beaucoup de complications désagréables avec op << ().

Autres conseils

Vous pourriez probablement plus facile en faisant quelque chose comme:

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;

Notez que vous ne devez pas jeter des chaînes comme vous êtes, d'où je std::runtime_error. Toutes les exceptions devraient provenir de std::exception qui runtime_error fait, de cette façon toutes les exceptions significatives peuvent être pris avec const std::exception&.

Cela fonctionne parce que la vie temporaire jusqu'à la fin de l'expression complète.

Certains opérateurs sont absents de la solution de 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;
};

En général, je crée mes propres classes d'exception. Il vous suffit de passer outre what() et peut fournir autant de constructeurs que vous le souhaitez. Pour construire le message d'erreur, il suffit d'utiliser vasprintf (si disponible) ou std :: ostringstream comme ci-dessus.

Voici un exemple:

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

Si vous n'avez pas vasprintf, vous pouvez également utiliser vsnprintf avec un tampon sur la pile ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top