写一个简单的 C++ 日志库 - cllogger(1)- enum class

        最近看了一些开源项目,他们封装了自己的日志库,各有所长,也温习了很多C++的基础知识,学以致用,从今天开始,从零开始写一个 C++ 的日志库。

        写日志库不是目的,目的是把技术细节梳理清晰,稳固所学。如果能对你有所帮助,那将是我最开心的事。

这个日志库将会很轻量,就叫 cllogger - c++ lite logger

目标

  • 轻量易用
  • 线程安全
  • 支持消息等级
  • 方便的格式化
  • 可输出到调试器
  • 可输出指定的文件

先看看 cllogger 的最终的使用方式:

cllogger& logger = GetLogger("D:\\app.log",true); // 第一个参数配置日志文件路径,第二个参数指定是否输出到调试器
logger.start();

如上两行便完成了日志库的配置、启动。随后即可调用不同等级的消息输出及格式化输出(以F结尾的函数),如:

    LogDebug(L"START");                // debug消息
    LogWarningF(L"APP %s","run");      // 支持格式化的警告消息
    LogError(L"Failed.");              // 异常消息
    LogFatal(L"Quit.");                // 严重错误消息

跑起来看看:

日志文件和控制台中的输出

足够简单吧?

简单的背后需要精心的构造,现在我们一步步来开始构建 cllogger

搭建个骨架

日志类需要哪些基础数据?消息等级、日志条目,那么我们把它们定义出来:


class cllogger {
public:
	enum class Level {
		Debug	= 0,
		Warning	= 1,
		Error	= 2,
		Fatal	= 3
	};

	struct Entry {
		Level level;
		std::wstring timestamp;
		std::wstring tag;
		std::wstring messsage;
	};

//...

}

Entry - 日志条目包含了 等级、时间戳、标识符、消息。

Level - 等级分为4类:调试、警告、错误、异常。

请注意 Level 这个枚举类型,我用了 enum class 类型,而不是 enum 类型,二者区别是什么呢?

enum class 和 enum

enum class Color { red, green, blue };  // C++11 enum class 

enum color { red, green, blue };       // C++98 "plain" enum

C++98 的 enum 为 弱枚举 又称为 非限定作用域枚举 

C++11 的 enum class 为 强枚举 又被称为 限定作用域枚举 

具体什么含义呢,逐一解释:

  • 类型安全性

        强弱指的是对类型检查,是否存在隐式转换。

        C++11 的 enum class 为 强枚举,意味着它不会隐式地转换为整数或其他enum class类型。只能显式转换,如通:

Color c = Color::blue;
auot i = static_cast<double>(c);

         C++98 的 enum 为 弱枚举 ,则被自动隐式转换:

    enum Color { red, green, blue };
    enum Animal { dog, cat, bird };

    Color color = Color::red;
    Animal animal = Animal::dog;

    if (color == animal) {
        std::cout << "red == dog" << std::endl;
    }

  • 作用域控制

   即限定枚举值作用域。

  C++11 的 enum class 的枚举值只在定义它的作用域内可见,是"域内枚举" (scoped enums),使用枚举量时,必须指明所属枚举类型,防止命名空间污染,如必须使用 Color::red 而不能直接使用 red 。

        而 C++98 的 enum 是 "非域内枚举"(unscoped enums),枚举值可以直接使用。

// C++11 enum class
Color c = Color::blue;

// C++98 enum
Color c = blue;

这就衍生一个问题,枚举量的名字泄露到了包含这个枚举类型的作用域内,简单地说,枚举值变量名在作用域内都不可再声明,因此 :

// C++98 enum
Color c = blue;

// Error!
auto blue = 1;
  • 前置声明

enum class 支持前置声明,即不用初始化枚举成员,声明一个枚举类型

enum class Color;  

 C++98中,弱枚举不支持前置声明,C++11中强、弱枚举都支持。弱枚举指定了基础类型就可以前置声明。

        注:C++20中可以 using 枚举类,这样也可以不使用类名,而直接使用枚举值了。

  • 指定底层表示类型

解决了不同平台上枚举类型大小不确定的问题。

enum class Color : unsigned int {
    Red = 0xFF0000,
    Green = 0x00FF00,
    Blue = 0x0000FF
};

int main() {
    Color c = Color::Red;
    std::cout << "The value of Red is: " << static_cast<unsigned int>(c) << std::endl;
    return 0;
}

C++11 之后的改进

C++11之后的版本继续改进了枚举的功能。例如,C++14引入了用户定义的枚举字面量,允许为枚举值定义更易读的字符串表示形式。

如何选择?

        首先,上面说了 enum class 的各种优点,当然它也有缺点。它的优点即缺点,如严苛的类型检查,必须使用类型名访问,主要就是麻烦一些。

        总的来说,一般情况下,优先enum class,但有时你也许正想利用enum可以隐式转换的特性,如:

enum week{Mon, Tue, Wed, Thur, Fri, Sat, Sun};

int main()
{
  enum week day;
  day = Wed;
  printf("%d",day);
  return 0;
}

具体到我们的 cllogger ,毫不犹豫的选择了 C++11 的 enum class。

至此,学习 enum class 让我们的 cllogger 迈出了一小步,后面将逐步丰满完善它,拭目以待 :)

参考

C++ Core Guidelines (isocpp.github.io)

C++ Core Guidelines

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x0007

可不可奖励我吃只毛嘴鸡 馋😋

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值