Question

my_macro << 1 << "hello world" << blah->getValue() << std::endl;

devrait se développer dans:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
Était-ce utile?

La solution

#define my_macro my_stream()
class my_stream: public std::ostringstream  {
public:
    my_stream() {}
    ~my_stream() {
        ThreadSafeLogging(this->str());
    }
};
int main() {
    my_macro << 1 << "hello world" << std::endl;
}

A temporaire de type my_stream est créé, qui est une sous-classe de ostringstream. Toutes les opérations à ce travail temporaire comme ils le feraient sur un ostringstream.

Lorsque la fin de la déclaration (ie. À droite après la virgule sur toute opération d'impression en main ()), l'objet temporaire est hors de portée et est détruite. Les appels Destructor my_stream ThreadSafeLogging avec les données "collectées" précédemment.

Tested (g ++).

Merci / crédits à dingo montrant comment simplifier la chose, donc je ne ai pas besoin du operator<< surchargé. ne peuvent pas être partagés trop mauvais upvotes.

Autres conseils

Ne pourriez-vous tirer seulement de ostream et fournir votre propre fil mise en œuvre en toute sécurité? Ensuite, vous pouvez simplement faire

myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;

Et obtenir exactement la même fonctionnalité sans macros et en C ++ correctement?

Non. Le problème est que sans utiliser la syntaxe de fonction, une macro est limitée à seulement être remplacé où il est.

Mais si vous étiez prêt à utiliser la syntaxe de fonction, vous pouvez remplacer des choses à la fois avant et après les args.

my_macro(1 << "hello world" << blah->getValue() << std::endl);

Vous pourriez en définissant MaMacro comme:

#define my_macro(args) std::ostreamstring oss; \
                       oss << args; \
                       ThreadSafeLogging(oss.str());

Jetez un oeil à google-glog , ils le font à l'aide d'un objet temporaire instancié avec un

LOG(INFO) << "log whatever" << 1;

et ils ont également d'autres macros intéressantes telles que LOG_IF et al.

Étant donné que vous avez ces lignes inclus quelque part dans votre code, oui il est possible

#include <iostream>
#include <sstream> 

macro __LINE__ est définie par tous les compilateurs standart. On peut donc l'utiliser pour générer un nom de variable Wich est différent à chaque fois que vous utilisez la macro:)

Voici une nouvelle version qui est considérée comme une instruction d'une seule déclaration: (Edited)

#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
     Var(s, __LINE__).x<2; ++Var(s, __LINE__).x)  \
    if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
    else Var(s, __LINE__).oss

// So you can use it like this 
int main() 
{ 
    if (4 != 2)
        my_macro << 4 << " hello "  << std::endl; 
    my_macro << 2 << " world !" << std::endl; 
} 

Developper ne sera probablement pas besoin d'utiliser cette macro deux fois sur la même ligne becasue de la simplicité de << opérateur. Mais dans le cas où vous avez besoin, vous pouvez changer l'utilisation de __LINE__ par __COUNTER__ (qui est non standard!). Merci à Quuxplusone pour cette astuce

Voici une autre vacherie j'ai vu ailleurs. Il a un inconvénient significatif par rapport à mon autre réponse: vous ne pouvez pas l'utiliser deux fois dans la même portée, car elle déclare une variable. Cependant, il peut encore être intéressant pour autre cas où vous voulez avoir somemacro foo lancer quelque chose après foo.

#define my_macro \
    std::ostringstream oss; \
    for (int x=0; x<2; ++x) \
        if (x==1) ThreadSafeLogging(oss.str()); \
        else oss

int main() {
    my_macro << 1 << "hello world" << std::endl;
}

La configuration de l'exploitation forestière j'est assez similaire:

bool ShouldLog(const char* file, size_t line, Priority prio);

class LoggerOutput : public std::stringstream {
public:
  LoggerOutput(const char* file, size_t line, Priority prio) 
  : prio(prio) 
  {
    Prefix(file, line, prio);
  }
  void Prefix(const char* file, size_t line, Priority prio);
  ~LoggerOutput() {
    Flush();
  }
  void Flush();
private:
  Priority prio;
};

#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)

Si votre enregistrement est désactivé, le ostream est jamais créé et peu existe au-dessus. Vous pouvez configurer la journalisation sur le numéro de nom de fichier et ligne (s) ou des niveaux de priorité. La fonction ShouldLog peut changer entre les invocations, de sorte que vous pouvez papillon ou limiter le rendement. La sortie du journal utilise deux fonctions à se modifier, le préfixe qui ajoute une « file: ligne: (PRIO) » préfixe à la ligne, et Flush () qui à la fois il évacue à la sortie du journal comme une seule commande et ajoute une nouvelle ligne à ce . Dans ma mise en œuvre, il le fait toujours, mais vous pouvez faire que sous condition si l'on est pas déjà.

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