Introduction

This article is meant to record my learning progress of Chapter 2 of "C++ Primer Plus 5". It primarily involves a deep dive into the source code analysis of the C++ library. Currently, I am a beginner and I am using the ChatGPT 3.5 model to aid in my learning.

I initially intended to continue reading, but due to my limited familiarity with C++ and the complexity of the project, I've decided to take it slow. My goal is to be able to understand and implement everything from scratch once I have learned enough. Additionally, I have a plan to analyze the STL (Standard Template Library) source code.

Summary of AI-Read Articles

This article serves as a study record of Chapter 2 of "C++ Primer Plus." It mainly discusses the implementation principles of C++ regular expressions and the std::regex_replace standard library function.

By dissecting the source code, it explains fundamental C++ concepts such as template syntax, static assertions, pre-processing compilation, and typedef alias definitions. Additionally, it mentions the learning plan for analyzing the STL source code.

std::regex_replace Function Principle

// Try replacing 'X' using regex
std::string cheese = "His X, How are you?"; // A string where we need to perform a replacement, 'X' is the value to replace
std::regex reg("X"); // Declare a regular expression object
std::string result = std::regex_replace(cheese, reg, "StarYuhen"); // Perform the replacement
std::cout << result << std::endl; // Output the result

Here, we follow the source code:

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;
}

This is the syntax structure of regex_replace. Let's analyze it step by step. The article previously covered template syntax, so I won't delve into it again.

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

This part represents the template syntax in a straightforward manner and uses inline to reduce overhead by inserting code at the function position, as mentioned earlier.

Continuing the Analysis:

First, let's look at this code:

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)

Here, the first parameter is:

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

It's defining a reference parameter __s that represents a reference to the template string basic_string<_Ch_type, _St, _Sa>&. Let's examine the source code:

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

Here, we find that the template for this class has the following parameters:

  • _CharT (the character type of the string)
  • _Traits (the allocator type of the string)
  • _Alloc (the storage type of the string)

Expanding Knowledge:

While examining the source code, we come across a special piece of code:

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

This is the C++ preprocessor conditional compilation (#if, #else, #endif). It allows you to compile specific code based on conditions, making the program more flexible and portable. typedef is a keyword used to define aliases.

In this part:

const basic_regex<_Ch_type, _Rx_traits>& __e

Let's take a look at the source code:

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");

Here, we introduce a new concept: the static_assert statement. It's a compile-time assertion, similar to the assert function in Java.

In this context:

is_same<_Ch_type, typename _Rx_traits::char_type>::value

It checks whether _Ch_type and _Rx_traits::char_type are the same.

Now, looking at the third parameter:

const _Ch_type* __fmt

This is used to format the replacement string, and it can be considered the most important part of this statement. It can be thought of as a formatting statement for regular expressions.

If we check the definition of _Ch_type in the source code:

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;

From the syntax, we can infer that:

  • char_type is an alias for _Ch_type and can be understood as the character type.
  • string_type is the type of std::basic_string<char_type>, which is known as the string type.
  • locale_type is an alias for std::locale, and it's also the localization type.

The third parameter is:

regex_constants::match_flag_type __flags = regex_constants::match_default

It defines it as an optional parameter. I find this interesting because I haven't learned this in C++ yet, so I researched to find out how to implement functions with default values. It's implemented as follows:

int FlagsDefault() {
  return 10 + 10;
}

// Default value parameter
int flagsInt(int Int = FlagsDefault()) {
  return Int + 1;
}

int main() {
  std::cout << flagsInt(10) << std::endl;
}

Here, if no parameter is passed, it adds 1 to the default value, otherwise, it adds 1 to the passed value.

Analyzing the Functional Code:

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

It starts by declaring an empty string __result. Then, it uses an overloaded version of regex_replace and employs std::back_inserter iterator to gradually add to __result, which can be thought of as an increment

operation.

When examining the source code, we come across a new keyword:

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

The explicit keyword is a specifier. It tells the compiler that it cannot perform implicit conversions.

I haven't been able to delve into more advanced knowledge, so this is all I've gathered for now.

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