前言

此文章用于记录自己学习C++ Primer Plus 5 的第二章学习记录,大多是深入了解C++库的源代码解析,现在还是小白,目前是配合ChatGPT的3.5模型进行学习记录。

**我本想继续翻阅,但是由于自身对于C++的陌生以及工程的大量,所以浅尝辄止,我希望等我学习的差不多的时候,我能够自己从零开始看,并且实现
,同时我希望阅读STL源码刨析,但是还需要点时间**

AI阅读文章总结

这篇文章是对C++ Primer Plus第二章的学习记录,
主要介绍了C++的正则表达式和标准库函数std::regex_replace的实现原理。

通过对源代码的解析,讲解了模板语法、静态断言、预处理编译和typedef别名定义等C++的基础知识。

此外,还提到了STL源码解析的学习计划。

std::regex_replace 函数原理

    // 尝试使用regex替换值
std::string cheese = "His X ,How are you?"; // 用于生成一个我们需要替换的字符串,其中X是我们需要替换的值
std::regex reg("X"); // 用于申明一个正则对象
std::string result = std::regex_replace(cheese, reg, "StarYuhen"); // 用于进行对象替换
std::cout << result << std::endl; // 最后输出

这里我们追寻一下源代码

  template<typename _Rx_traits, typename _Ch_type,
typename _St, typename _Sa>
inline basic_string<_Ch_type, _St, _Sa>
regex_replace(const basic_string<_Ch_type, _St, _Sa>& __s,
const basic_regex<_Ch_type, _Rx_traits>& __e,
const _Ch_type* __fmt,
regex_constants::match_flag_type __flags
= regex_constants::match_default)
{
basic_string<_Ch_type, _St, _Sa> __result;
regex_replace(std::back_inserter(__result),
__s.begin(), __s.end(), __e, __fmt, __flags);
return __result;
}

这是其中regex_replace的语法构成,我们逐步分析,由于前面的一篇文章,我们已经讲述了模板语法的内容,这里就不做讲解了。

template<typename _Rx_traits, typename _Ch_type,
typename _St, typename _Sa>
inline basic_string<_Ch_type, _St, _Sa> 

这一段就是通俗的模板语法,并且使用inline插入代码到函数位置减少开销,也在上文提到过


开始解析:
首先看这一段的代码:

 regex_replace(const basic_string<_Ch_type, _St, _Sa>& __s,
const basic_regex<_Ch_type, _Rx_traits>& __e,
const _Ch_type* __fmt,
regex_constants::match_flag_type __flags
= regex_constants::match_default)

这里的传参列表一:

  • const basic_string<_Ch_type, _St, _Sa>& __s

他的意思是定义一个引用类型的参数__s,表示模板字符串的引用 basic_string<_Ch_type, _St, _Sa>& ,我们查看源代码:

  template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string

在这里我们会发现这个类的模板语法定义的传参分别是
_CharT(字符串的字符类型),
_Traits(字符串的分配器类型),
_Alloc(字符串的储存方式).


扩展知识~:

从刚才的源码查找我们会发现下面一段特殊的代码:

#if __cplusplus < 201103L
      typedef iterator __const_iterator;
#else
      typedef const_iterator __const_iterator;
#endif

这是C++的预条件处理编译(预处理器的条件编译),#if,#else,#endif 应该都能看懂吧.

预条件处理编译能够根据特定的条件选择是否编译对应代码,可以让程序更加灵活和可移植。

而typedef用于定义别名的关键字


这里的传参列表二:

  • const basic_regex<_Ch_type, _Rx_traits>& __e

这里我们跳转源代码看看:

  template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type>>
class basic_regex
{
public:
static_assert(is_same<_Ch_type, typename _Rx_traits::char_type>::value,
"regex traits class must have the same char_type");

这里我们引用新的知识 static_assert 语句,他是一个编译时断言,和Java的Test测试库中的Assert类似。

is_same<_Ch_type, typename _Rx_traits::char_type>::value
的意思是判断_Ch_type和_Rx_traits::char_type 是否相同


这里的传参列表三:

  • const _Ch_type* __fmt,

他是用于替换字符串的格式,你可以把他看作这个语句最重要的部分,它可以看作是一个正则的格式化语句.

而后我面我翻阅源码发现_Ch_type的定义:

  template<typename _Ch_type>
class regex_traits
{
public:
typedef _Ch_type                char_type;
typedef std::basic_string<char_type>    string_type;
typedef std::locale            locale_type;

从语法上我们看出

  • char_type是_Ch_type的别名,同时理解为字符类型
  • string_type 是std::basic_string<char_type>模板的类型,被称为字符串类型
  • locale_type则是std::locale的别名,他又是本地化类型

**我本想继续翻阅,但是由于自身对于C++的陌生以及工程的大量,所以浅尝辄止,我希望等我学习的差不多的时候,我能够自己从零开始看,并且实现
,同时我希望阅读STL源码刨析,但是还需要点时间**


传参三:

  • regex_constants::match_flag_type __flags
    = regex_constants::match_default

他定义了他为可选参数,这个我很新奇,因为还未在C++中学习过,于是我查找资料想要实现函数设置默认值的代码,
实现如下:

int FlagsDefault() {
    return 10 + 10;
}

// 默认值参数
int flagsInt(int Int = FlagsDefault()) {
    return Int+1;
}

main(){
        // 输出默认值的函数
    std::cout << flagsInt(10) << std::endl;
}

我们会发现,若是没有传入参数,会按照默认值进行+1,如何传入了值则会用传入值进行+1.


开始解析功能代码:

      basic_string<_Ch_type, _St, _Sa> __result;
      regex_replace(std::back_inserter(__result),
            __s.begin(), __s.end(), __e, __fmt, __flags);
      return __result;

先申明一个空字符串,__result,而后使用regex_replace的重载函数并使用std::back_inserter迭代器
逐渐增加到__result中,可以看作是++操作。

翻阅源代码发现一个新的关键字:

      /// The only way to create this %iterator is with a container.
      explicit _GLIBCXX20_CONSTEXPR
      back_insert_iterator(_Container& __x)
      : container(std::__addressof(__x)) { }

explicit 关键字为修饰词,这个关键字告诉编译器他不能被隐性转换。

其他更深入的知识暂时了解不到,所以目前收获就这些。

最后修改:2023 年 04 月 07 日
如果觉得我的文章对你有用,请随意赞赏