From b122fcdf4d56395793ac788373774c4cb9054ee4 Mon Sep 17 00:00:00 2001 From: Matrix-A <51079060+Matrix-A@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:19:35 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=AC=AC15=E9=A2=98?= =?UTF-8?q?=E6=A0=87=E5=87=86=E7=AD=94=E6=A1=88=E9=9A=BE=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f14003f7..9aa7de52 100644 --- a/README.md +++ b/README.md @@ -2255,7 +2255,7 @@ int main() 4.73472, 4.05709, 5.038, 5.08264, 5.73076, 5.18673, ``` -- 难度: 待定 +- 难度: **★★★☆☆** 学习链接: @@ -2276,6 +2276,71 @@ int main() ### 标准答案 +顾名思义,**表达式模板**指使用模板类表示表达式。表达式由**运算符**和**操作数**按照一定规律组合而成。 + +观察题目中的表达式为 `a - b * c / d + e` 可知: + +1. 运算符:可以使用标准库中的通透的[**运算符函数对象**](https://zh.cppreference.com/w/cpp/utility/functional#.E9.80.9A.E9.80.8F.E5.87.BD.E6.95.B0.E5.AF.B9.E8.B1.A1)进行记录; +2. 操作数:均为二元运算符,需要记录**左操作数**和**右操作数**; + +以 `a - b * c / d + e` 中的子表达式 `/` 为例,其运算符可以使用 `std::divides` ,左操作数为**表达式模板类对象** `b * c` ,右操作数为 `d` 。 + +根据以上内容,通过在**重载运算符**生成**表达式模板类对象**,并在**表达式模板类**的 `operator[]` 中将**运算符函数对象**应用到**操作数**就可以简单的完成题目,示例代码如下: + +``` +template +struct vector_expr { + const F& func; + const L& lhs; + const R& rhs; + + std::size_t size() const { + return std::min(lhs.size(), rhs.size()); + } + inline auto operator[](const size_t idx) const { + return func(lhs[idx], rhs[idx]); + } +}; + +auto operator+(const auto& lhs, const auto& rhs) { + return vector_expr{ std::plus{}, lhs, rhs }; +} +auto operator-(const auto& lhs, const auto& rhs) { + return vector_expr{ std::minus{}, lhs, rhs }; +} +auto operator*(const auto& lhs, const auto& rhs) { + return vector_expr{ std::multiplies{}, lhs, rhs }; +} +auto operator/(const auto& lhs, const auto& rhs) { + return vector_expr{ std::divides{}, lhs, rhs }; +} +``` + +在以上代码中,使用**表达式模板**通过**惰性求值**将**运算符函数对象**应用到**操作数**,这就是范围库中 [`std::ranges::zip_transform_view`](https://zh.cppreference.com/w/cpp/ranges/zip_transform_view)(C++23)。 + +将上述代码替换为以下内容,也可以正确执行: + +``` +auto operator+(const auto& lhs, const auto& rhs) { + return std::ranges::zip_transform_view{ std::plus{}, lhs, rhs }; +} +auto operator-(const auto& lhs, const auto& rhs) { + return std::ranges::zip_transform_view{ std::minus{}, lhs, rhs }; +} +auto operator*(const auto& lhs, const auto& rhs) { + return std::ranges::zip_transform_view{ std::multiplies{}, lhs, rhs }; +} +auto operator/(const auto& lhs, const auto& rhs) { + return std::ranges::zip_transform_view{ std::divides{}, lhs, rhs }; +} +``` + +综上所述,本题的**表达式模板**就是简化版的 `std::ranges::zip_transform_view`。 + +我们只需要为**表达式模板**增加**亿**点点细节,就可以自行实现范围库了!🥳 + +> 使用**表达式模板**或范围库的原因:在提供更通用、更灵活的表达式计算的同时充分利用编译器优化,如内联、并行计算等。 + --- From 6da194b72846cbe9448db668d57eb7780ba694d5 Mon Sep 17 00:00:00 2001 From: Matrix-A <51079060+Matrix-A@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:25:49 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9aa7de52..c30483fb 100644 --- a/README.md +++ b/README.md @@ -2287,7 +2287,7 @@ int main() 根据以上内容,通过在**重载运算符**生成**表达式模板类对象**,并在**表达式模板类**的 `operator[]` 中将**运算符函数对象**应用到**操作数**就可以简单的完成题目,示例代码如下: -``` +```cpp template struct vector_expr { const F& func; @@ -2320,7 +2320,7 @@ auto operator/(const auto& lhs, const auto& rhs) { 将上述代码替换为以下内容,也可以正确执行: -``` +```cpp auto operator+(const auto& lhs, const auto& rhs) { return std::ranges::zip_transform_view{ std::plus{}, lhs, rhs }; } From 73a1ec83c553b9ef851e4aa07308abdf3eb236a9 Mon Sep 17 00:00:00 2001 From: Matrix-A <51079060+Matrix-A@users.noreply.github.com> Date: Thu, 29 Feb 2024 21:49:20 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c30483fb..682dc173 100644 --- a/README.md +++ b/README.md @@ -2276,17 +2276,6 @@ int main() ### 标准答案 -顾名思义,**表达式模板**指使用模板类表示表达式。表达式由**运算符**和**操作数**按照一定规律组合而成。 - -观察题目中的表达式为 `a - b * c / d + e` 可知: - -1. 运算符:可以使用标准库中的通透的[**运算符函数对象**](https://zh.cppreference.com/w/cpp/utility/functional#.E9.80.9A.E9.80.8F.E5.87.BD.E6.95.B0.E5.AF.B9.E8.B1.A1)进行记录; -2. 操作数:均为二元运算符,需要记录**左操作数**和**右操作数**; - -以 `a - b * c / d + e` 中的子表达式 `/` 为例,其运算符可以使用 `std::divides` ,左操作数为**表达式模板类对象** `b * c` ,右操作数为 `d` 。 - -根据以上内容,通过在**重载运算符**生成**表达式模板类对象**,并在**表达式模板类**的 `operator[]` 中将**运算符函数对象**应用到**操作数**就可以简单的完成题目,示例代码如下: - ```cpp template struct vector_expr { @@ -2316,6 +2305,17 @@ auto operator/(const auto& lhs, const auto& rhs) { } ``` +顾名思义,**表达式模板**指使用模板类表示表达式。表达式由**运算符**和**操作数**按照一定规律组合而成。 + +观察题目中的表达式为 `a - b * c / d + e` 可知: + +1. 运算符:可以使用标准库中的通透的[**运算符函数对象**](https://zh.cppreference.com/w/cpp/utility/functional#.E9.80.9A.E9.80.8F.E5.87.BD.E6.95.B0.E5.AF.B9.E8.B1.A1)进行记录; +2. 操作数:均为二元运算符,需要记录**左操作数**和**右操作数**; + +以 `a - b * c / d + e` 中的子表达式 `/` 为例,其运算符可以使用 `std::divides` ,左操作数为**表达式模板类对象** `b * c` ,右操作数为 `d` 。 + +根据以上内容,通过在**重载运算符**生成**表达式模板类对象**,并在**表达式模板类**的 `operator[]` 中将**运算符函数对象**应用到**操作数**就可以简单的完成题目。 + 在以上代码中,使用**表达式模板**通过**惰性求值**将**运算符函数对象**应用到**操作数**,这就是范围库中 [`std::ranges::zip_transform_view`](https://zh.cppreference.com/w/cpp/ranges/zip_transform_view)(C++23)。 将上述代码替换为以下内容,也可以正确执行: From 3f028d61985795bdae9627f6a558b965297d92ff Mon Sep 17 00:00:00 2001 From: Matrix-A <51079060+Matrix-A@users.noreply.github.com> Date: Fri, 1 Mar 2024 11:26:33 +0800 Subject: [PATCH 4/4] Update README.md --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 682dc173..b4e0392c 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ - [`15` 表达式模板](#15-表达式模板) + [群友提交](#群友提交-14) + [标准答案](#标准答案-14) + + [解析](#解析-3) - [`16` 通透函数宏](#16-制造传递函数模板的宏) + [群友提交](#群友提交-15) + [标准答案](#标准答案-15) @@ -2305,6 +2306,19 @@ auto operator/(const auto& lhs, const auto& rhs) { } ``` +**表达式模板**是简化版的 `std::ranges::zip_transform_view`。 + +优点:灵活,易用,可以充分利用编译器优化 + +缺点:实现复杂 + + + +
+ 解析 + +### 解析 + 顾名思义,**表达式模板**指使用模板类表示表达式。表达式由**运算符**和**操作数**按照一定规律组合而成。 观察题目中的表达式为 `a - b * c / d + e` 可知: @@ -2337,9 +2351,7 @@ auto operator/(const auto& lhs, const auto& rhs) { 综上所述,本题的**表达式模板**就是简化版的 `std::ranges::zip_transform_view`。 -我们只需要为**表达式模板**增加**亿**点点细节,就可以自行实现范围库了!🥳 - -> 使用**表达式模板**或范围库的原因:在提供更通用、更灵活的表达式计算的同时充分利用编译器优化,如内联、并行计算等。 +我们只需要为**表达式模板**增加**亿**点点细节,就可以自行实现范围库了!🥳🥳🥳