c++字符特性模板,到底是什么?
作为一个老程序员,也一直对它觉得很是模糊和神秘,这到底是个什么东西,需要揭开这个面纱了.
怎么揭开,相关文档看不到,就剩下看代码了. 我的环境是ubuntu20, c++库是libstdc++-9-dev
打开/usr/include/c++/9/bits/char_traits.h, 这就是char_traits 的真身了.
它分为3个部分:
第一部分是 __gnu_cxx, 占据47-213行
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
} // namespace
第2,3部分是 std 命名空间, 分成两段,共占据215-841行
namespace std _GLIBCXX_VISIBILITY(default)
{
}
就分析一下gnu 的吧,它代码比较少。说明问题为主,并最后给出一个测试.
它又分为声明部分,若干个函数实现部分,我就分析声明部分吧,它包含了几个简单的实现,
复杂的实现它放到了后面部分中,为简化把较复杂代码忽略了。
摘录下核心部分,75行,这部分代码可以和我的测试代码构成一个编译工程.
#include <bits/stl_algobase.h>
#include <bits/postypes.h>
template<typename _T>
struct _Any_Struct
{
//定义变量别名, 只不过它限定在一个struct 结构中
//如果去掉 template<typename _CharT> 模板限制,
//再去掉 struct _Char_types 限制,
// 就是不加任何限制来重定义变量别名,那就是c了, 就看懂了,只是范围就放开了.
// 外部看等价于typedef unsigned long _Any_Struct<_T>::int_type
typedef unsigned long int_type;
typedef std::streampos pos_type;
typedef std::streamoff off_type;
typedef std::mbstate_t state_type;
};
template<typename _T>
struct char_traits
{
//再次重新定义变量别名,定义别名,只是为了使用时通俗化一点
typedef _T char_type;
typedef typename _Any_Struct<_T>::int_type int_type;
typedef typename _Any_Struct<_T>::pos_type pos_type;
typedef typename _Any_Struct<_T>::off_type off_type;
typedef typename _Any_Struct<_T>::state_type state_type;
//static 是说,我这个函数是不需要this 指针的.
//constexpr 是说, 函数是常量表达式, 在编译阶段就确定了函数形式
//如果去掉char_traits 包装, 这跟普通的c 函数没有什么两样.
static constexpr void
assign(char_type& __c1, const char_type& __c2)
{ __c1 = __c2; }
static constexpr bool
eq(const char_type& __c1, const char_type& __c2)
{ return __c1 == __c2; }
static constexpr bool
lt(const char_type& __c1, const char_type& __c2)
{ return __c1 < __c2; }
static constexpr int
compare(const char_type* __s1, const char_type* __s2, std::size_t __n);
static constexpr std::size_t
length(const char_type* __s);
static constexpr const char_type*
find(const char_type* __s, std::size_t __n, const char_type& __a);
static constexpr char_type*
move(char_type* __s1, const char_type* __s2, std::size_t __n);
static constexpr char_type*
copy(char_type* __s1, const char_type* __s2, std::size_t __n);
static constexpr char_type*
assign(char_type* __s, std::size_t __n, char_type __a);
static constexpr char_type
to_char_type(const int_type& __c)
{ return static_cast<char_type>(__c); }
static constexpr int_type
to_int_type(const char_type& __c)
{ return static_cast<int_type>(__c); }
static constexpr bool
eq_int_type(const int_type& __c1, const int_type& __c2)
{ return __c1 == __c2; }
static constexpr int_type
eof()
{ return static_cast<int_type>(_GLIBCXX_STDIO_EOF); }
static constexpr int_type
not_eof(const int_type& __c)
{ return !eq_int_type(__c, eof()) ? __c : to_int_type(char_type()); }
};
放上我的测试代码:
#include <stdio.h>
#include "char_traits.h"
int main()
{
char c1='a';
char c2='b';
char_traits<char>::assign(c1,c2); //类型charT给的是char, 所以参数就可以用char类型变量了
printf("now c1 is:%c\n",c1);
bool ret=char_traits<char>::eq(c1,c2);
printf("eq ret:%d\n",ret);
// 测试代码没有实现比较函数,如果想测试可以继续copy加入其对应实现部分
// int iret=char_traits<char>::compare((const char*)c1,(const char *)c2,sizeof(char));
// printf("compare iret:%d\n",iret);
return 0;
}
小结:
char_traits: 字符属性类. 处理的是字符类型
在它的命名空间下,实现了以下基本操作函数,
字符赋值,相等判别,小于判别,比较函数,长度,查找,移动,拷贝,类型变换,文件尾字符判别等。
如果忽略命名空间,再固定上变量类型,那它就是纯c 函数.
字符属性类也没有什么神秘性了,它是字符操作的一组函数,放到了char_traits 结构下.
你还可以扩展一些你想要的函数.
char_traits 可以认为它啥都不是,就是一个限定字符,就是限制到或精确到某某结构下的某某变量.
char_traits<char> 是说我后面操作的数据类型是char 类型. 习惯了就好了,计算机需要严格定义.