使用自定义字面量简化常量的定义
在涉及文件大小的代码中,经常要写出判断大小的代码。例如,在上传文件之前,要判断文件的大小是否超出了可支持的范围:
1 | if (file_size > 4 * 1024 * 1024 * 1024) { |
这里出现了好几个1024,阅读这段代码的人首先要心算一遍之后才能理解“哦,原来这里的文件大小上限是4GB”。对程序员来说这种计算都是小菜一碟,即便如此,这段代码的可读性也是不高的,因为它没有直截了当地表达出它的意图。
有几种方法可以优化这段代码,例如抽取出一个GB()
函数。这里要介绍的是另一种表达更自然的方法,C++11引入的新特性:自定义字面量。
字面量是指在代码中写下的数字、字符串等值,例如:
- 整数,如
1024
。 - 浮点数,如
3.14
。 - 字符,如
'a'
。 - 字符串,如
"abc"
。
如果在字面量后面加上特定后缀,可以调用对应的转换函数,将这个字面量转成特定类型。例如,在<string>
中定义了s
后缀,可以将一个字符串字面量转换成std::string
类型:
1 |
|
我们也可以定义自己的字面量后缀和转换函数,方法是定义一个字面量操作符函数。该函数的语法如下:
1 | ReturnType operator"" _Suffix(Parameters); |
ReturnType
是这个转换函数的返回值。_Suffix
是字面量的后缀,要注意的是,开发者自定义字面量的后缀必须以_
字符开头,否则会编译失败,因为不带这个字符开头的后缀是预留给C++的。Parameters
是转换函数的参数列表,可以从以下几种参数列表中选择:
1 | //整数字面量 |
具体选择哪种参数列表,根据你的需求而定。如果你希望只支持整数,那么只需要定义一个参数列表是(unsigned long long)
的操作符函数即可;如果你希望同时支持整数和浮点数,那么就要定义两个操作符函数,参数列表分别是(unsigned long long)
和(long double)
。
你只能从上面的参数列表中选择,不能使用别的参数列表,否则编译会失败。例如,即使你只需要一个int
类型的整数字面量,也必须把参数定义成unsigned long long
。编译器总是把字面量的值以可表示范围最大的类型传给你,具体怎么使用这个值由你自己决定。
由于C++中存在四种字符类型,所以字符字面量和字符串字面量都分别有四种参数类型。在字符串字面量的参数列表中,第二个size_t
类型的参数表示字符串的长度。
如果字面量操作符函数的参数列表定义成const char*
,那么它是一个原始字面量操作符函数。原始字面量操作符只能用在整数或浮点数字面量上,它的参数指向整数或浮点数的字符串。它提供了一种方法,让我们可以以自定义的规则来解析整数或浮点数字面量。
回到本文开头的问题,我们可以定义下面的字面量操作符函数来简化文件大小常量的定义:
1 | constexpr std::int64_t operator"" _GB(unsigned long long value) { |
替换使用这个自定义字面量之后,代码含义一目了然,大大提高了可读性:
1 | if (file_size > 4_GB) { |