如何为模板专业化创建类型标签

发布于 2024-09-16 09:23:02 字数 733 浏览 12 评论 0原文

我有一个自定义日志记录类,它通过模板化的运算符支持iostream语法:

template< class T >
MyLoggingClass & operator <<(MyLoggingClass &, const T &) {
    // do stuff
}

我还有一个该运算符的专门版本,应该在以下情况下调用 :一条日志消息已完成:

template< >
MyLoggingClass & operator <<(MyLoggingClass &, consts EndOfMessageType &){
    // build the message and process it
}

EndOfMessageType 的定义如下:

class EndOfMessageType {};
const EndOfMessageType eom = EndOfMessageType( );

定义了全局常量 eom,以便用户可以像 std::endl 一样使用它code> 在日志消息的末尾。我的问题是,这个解决方案是否有任何陷阱,或者是否有一些既定的模式可以做到这一点?

提前致谢!

I have a custom logging class that supports iostream-syntax via a templated operator <<:

template< class T >
MyLoggingClass & operator <<(MyLoggingClass &, const T &) {
    // do stuff
}

I also have a specialized version of this operator that is supposed to be called when a log-message is complete:

template< >
MyLoggingClass & operator <<(MyLoggingClass &, consts EndOfMessageType &){
    // build the message and process it
}

EndOfMessageType is defined like this:

class EndOfMessageType {};
const EndOfMessageType eom = EndOfMessageType( );

The global constant eom is defined so that users can use it just like std::endl at the end of their log-messages. My question is, are there any pitfalls to this solution, or is there some established pattern to do this?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

云雾 2024-09-23 09:23:02

std::endl 是一个函数,而不是一个对象,并且 operator<< 被重载,用于接受指向函数的指针,并返回对 ostream 的引用。此重载仅调用该函数并传递*this

#include <iostream>

int main()
{
    std::cout << "Let's end this line now";
    std::endl(std::cout); //this is the result of cout << endl, or cout << &endl ;) 
}

只是考虑的替代方案。

顺便说一句,我认为没有必要对运算符进行专门化:普通的重载即使不是更好,也同样可以。

std::endl is a function, not an object, and operator<< is overloaded for accepting a pointer to a function taking and returning a reference to ostream. This overload just calls the function and passes *this.

#include <iostream>

int main()
{
    std::cout << "Let's end this line now";
    std::endl(std::cout); //this is the result of cout << endl, or cout << &endl ;) 
}

Just an alternative to consider.

By the way, I don't think there is any need to specialize the operator: a normal overload does just as well, if not better.

顾冷 2024-09-23 09:23:02

我认为你的解决方案是可以接受的。如果您想以不同的方式执行此操作,您可以创建一个 Message 类,该类将代替您的 MyLoggingClass 并提供自动终止功能。

{
  Message m;
  m << "Line: " << l; // or m << line(l) 
  m << "Message: foo"; // or m << message("foo");
  log << m; // this would automatically format the message
}

I think your solution is acceptable. If you wanted to do it differently, you could create a class Message, that would be used instead of the your MyLoggingClass and provided automatic termination.

{
  Message m;
  m << "Line: " << l; // or m << line(l) 
  m << "Message: foo"; // or m << message("foo");
  log << m; // this would automatically format the message
}
栩栩如生 2024-09-23 09:23:02

我已经这样做这样,就像其他一些人们做到了。有一个函数 Error / Log / Warning / 等,看起来像这样

DiagnosticBuilder Error( ErrType type, string msg, int line );

这将返回一个临时构建器对象,其类基本上定义为

struct DiagnosticBuilder {
  DiagnosticBuilder(std::string const& format)
    :m_emit(true), m_format(format) 
  { }
  DiagnosticBuilder(DiagnosticBuilder const& other) 
    :m_emit(other.m_emit), m_format(other.m_format), m_args(other.m_args) {
    other.m_emit = false;
  }
  ~DiagnosticBuilder() {
    if(m_emit) {
      /* iterate over m_format, and print the next arg 
         everytime you hit '%' */
    }
  }

  DiagnosticBuilder &operator<<(string const& s) {
    m_args.push_back(s);
    return *this;
  }
  DiagnosticBuilder &operator<<(int n) {
    std::ostringstream oss; oss << n;
    m_args.push_back(oss.str());
    return *this;
  }
  // ...
private:
  mutable bool m_emit;
  std::string m_format;
  std::vector<std::string> m_args;
};

因此,如果您在循环中构建日志消息,那么

DiagnosticBuilder b(Error("The data is: %"));
/* do some loop */
b << result;

只要自动调用构建器的析构函数,就会发出该消息。大多数情况下您会匿名使用它

Error("Hello %, my name is %") << "dear" << "litb";

I have done it this way, like some other people did. Have a function Error / Log / Warning / etc that could look like this

DiagnosticBuilder Error( ErrType type, string msg, int line );

This will return a temporary builder object, whose class is basically defined like

struct DiagnosticBuilder {
  DiagnosticBuilder(std::string const& format)
    :m_emit(true), m_format(format) 
  { }
  DiagnosticBuilder(DiagnosticBuilder const& other) 
    :m_emit(other.m_emit), m_format(other.m_format), m_args(other.m_args) {
    other.m_emit = false;
  }
  ~DiagnosticBuilder() {
    if(m_emit) {
      /* iterate over m_format, and print the next arg 
         everytime you hit '%' */
    }
  }

  DiagnosticBuilder &operator<<(string const& s) {
    m_args.push_back(s);
    return *this;
  }
  DiagnosticBuilder &operator<<(int n) {
    std::ostringstream oss; oss << n;
    m_args.push_back(oss.str());
    return *this;
  }
  // ...
private:
  mutable bool m_emit;
  std::string m_format;
  std::vector<std::string> m_args;
};

So if you are building a log message in a loop, be it so

DiagnosticBuilder b(Error("The data is: %"));
/* do some loop */
b << result;

As soon as the builder's destructor is called automatically, the message is emitted. Mostly you would use it anonymously

Error("Hello %, my name is %") << "dear" << "litb";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文