C++ Boost Phoenix库示例分析使用

目录
  • 一、说明
  • 二、预先知道Boost.Phoenix
  • 三、示例和代码

一、说明

在函数式编程模型中,函数是对象,与其他对象一样,可以作为参数传递给函数或存储在容器中。有许多支持函数式编程模型的 Boost 库。

  • Boost.Phoenix 是这些库中最广泛、也是最重要的库。它取代了库 Boost.Lambda,它被简要介绍,但只是为了完整性。
  • Boost.Function 提供了一个类,可以轻松定义函数指针,而无需使用源自 C 编程语言的语法。
  • Boost.Bind 是一个适配器,即使实际签名与预期签名不同,它也允许您将函数作为参数传递给其他函数。
  • Boost.Ref 可用于传递对对象的引用,即使函数通过副本传递参数。
  • Boost.Lambda 可以称为 Boost.Phoenix 的前身。它是一个相当古老的库,并且在将 C++11 添加到编程语言之前很多年就允许使用 lambda 函数。

二、预先知道Boost.Phoenix

Boost.Phoenix 是函数式编程最重要的 Boost 库。虽然 Boost.Bind 或 Boost.Lambda 等库为函数式编程提供了一些支持,但 Boost.Phoenix 包含这些库的功能并超越了它们。

在函数式编程中,函数是对象,可以像对象一样处理。使用 Boost.Phoenix,一个函数可以返回另一个函数作为结果。也可以将一个函数作为参数传递给另一个函数。因为函数是对象,所以可以区分实例化和执行。访问一个函数不等于执行它。

Boost.Phoenix 支持使用函数对象进行函数式编程:函数是基于类的对象,这些类重载了运算符 operator()。这样,函数对象的行为就像 C++ 中的其他对象一样。例如,它们可以被复制并存储在容器中。但是,它们的行为也类似于函数,因为它们可以被调用。

函数式编程在 C++ 中并不新鲜。您可以将一个函数作为参数传递给另一个函数,而无需使用 Boost.Phoenix。

三、示例和代码

示例 39.1。谓词作为全局函数、lambda 函数和 Phoenix 函数

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
bool is_odd(int i) { return i % 2 == 1; }
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  std::cout << std::count_if(v.begin(), v.end(), is_odd) << '\n';
  auto lambda = [](int i){ return i % 2 == 1; };
  std::cout << std::count_if(v.begin(), v.end(), lambda) << '\n';
  using namespace boost::phoenix::placeholders;
  auto phoenix = arg1 % 2 == 1;
  std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n';
}

Example39.1

示例 39.1 使用算法 std::count_if() 来计算向量 v 中的奇数。std::count_if() 被调用 3 次,一次使用谓词作为独立函数,一次使用 lambda 函数,一次使用凤凰功能。

Phoenix 函数与独立函数和 lambda 函数不同,因为它没有框架。虽然其他两个函数有一个带有签名的函数头,但 Phoenix 函数似乎只包含一个函数体。

Phoenix 函数的关键组件是 boost::phoenix::placeholders::arg1。 arg1 是函数对象的全局实例。您可以像 std::cout 一样使用它:一旦包含相应的头文件,这些对象就会存在。

arg1 用于定义一元函数。表达式 arg1 % 2 == 1 创建一个需要一个参数的新函数。该函数不会立即执行,而是存储在 Phoenix 中。 phoenix 被传递给 std::count_if() ,它为 v 中的每个数字调用谓词。

arg1 是调用 Phoenix 函数时传递的值的占位符。由于此处仅使用了 arg1,因此创建了一个一元函数。 Boost.Phoenix 提供了额外的占位符,例如 boost::phoenix::placeholders::arg2 和 boost::phoenix::placeholders::arg3。 Phoenix 函数总是期望与具有最大数量的占位符一样多的参数。

Example39.1

示例 39.1 将 3 写入标准输出 3 次。

示例 39.2。 Phoenix 函数与 lambda 函数

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  auto lambda = [](int i){ return i % 2 == 1; };
  std::cout << std::count_if(v.begin(), v.end(), lambda) << '\n';
  std::vector<long> v2;
  v2.insert(v2.begin(), v.begin(), v.end());
  using namespace boost::phoenix::placeholders;
  auto phoenix = arg1 % 2 == 1;
  std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n';
  std::cout << std::count_if(v2.begin(), v2.end(), phoenix) << '\n';
}

Example39.2

例 39.2 强调了 Phoenix 和 lambda 函数之间的一个关键区别。除了不需要带有参数列表的函数头之外,Phoenix 函数参数没有类型。 lambda 函数 lambda 需要一个 int 类型的参数。 Phoenix 函数 phoenix 将接受模运算符可以处理的任何类型。

将 Phoenix 函数视为函数模板。像函数模板一样,Phoenix 函数可以接受任何类型。这使得在示例 39.2 中可以使用 phoenix 作为容器 v 和 v2 的谓词,即使它们存储不同类型的数字。如果您尝试将谓词 lambda 与 v2 一起使用,则会出现编译器错误。

示例 39.3。 Phoenix 用作延迟 C++ 代码

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  using namespace boost::phoenix::placeholders;
  auto phoenix = arg1 > 2 && arg1 % 2 == 1;
  std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n';
}

Example39.3

示例 39.3 使用 Phoenix 函数作为谓词,使用 std::count_if() 计算大于 2 的奇数。Phoenix 函数访问 arg1 两次:一次测试占位符是否大于 2,一次测试它是否为奇数.条件与 && 相关联。

您可以将 Phoenix 函数视为不会立即执行的 C++ 代码。示例 39.3 中的 Phoenix 函数看起来像一个使用多个逻辑和算术运算符的条件。但是,条件不会立即执行。它仅在从 std::count_if() 中访问时执行。 std::count_if() 中的访问是正常的函数调用。

示例 39.3 将 2 写入标准输出。

示例 39.4。显式 Phoenix 类型

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  using namespace boost::phoenix;
  using namespace boost::phoenix::placeholders;
  auto phoenix = arg1 > val(2) && arg1 % val(2) == val(1);
  std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n';
}

Example39.4

例 39.4 对 Phoenix 函数中的所有操作数使用显式类型。严格来说,你看不到类型,只有辅助函数 boost::phoenix::val()。此函数返回使用传递给 boost::phoenix::val() 的值初始化的函数对象。函数对象的实际类型无关紧要。重要的是 Boost.Phoenix 为不同类型重载了运算符,如 >、&&、% 和 ==。因此,不会立即检查条件。相反,函数对象被组合以创建更强大的函数对象。根据操作数,它们可能会自动用作函数对象。否则,您可以调用 val() 等辅助函数。

示例 39.5。 boost::phoenix::placeholders::arg1 和 boost::phoenix::val()

#include <boost/phoenix/phoenix.hpp>
#include <iostream>
int main()
{
  using namespace boost::phoenix::placeholders;
  std::cout << arg1(1, 2, 3, 4, 5) << '\n';
  auto v = boost::phoenix::val(2);
  std::cout << v() << '\n';
}

Example39.5

示例 39.5 说明了 arg1 和 val() 如何工作。 arg1 是函数对象的实例。它可以直接使用,也可以像函数一样调用。您可以传递任意数量的参数——arg1 返回第一个参数。

val() 是一个用于创建函数对象实例的函数。函数对象使用作为参数传递的值进行初始化。如果实例像函数一样被访问,则返回该值。

示例 39.5 将 1 和 2 写入标准输出。

示例 39.6。创建自己的 Phoenix 函数

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
struct is_odd_impl
{
    typedef bool result_type;

    template <typename T>
    bool operator()(T t) const { return t % 2 == 1; }
};
boost::phoenix::function<is_odd_impl> is_odd;
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  using namespace boost::phoenix::placeholders;
  std::cout << std::count_if(v.begin(), v.end(), is_odd(arg1)) << '\n';
}

Example39.6

示例 39.6 解释了如何创建自己的 Phoenix 函数。您将函数对象传递给模板 boost::phoenix::function。该示例传递了 is_odd_impl 类。此类重载运算符 operator():当传入奇数时,运算符返回 true。否则,运算符返回 false。

请注意,您必须定义类型result_type。 Boost.Phoenix 使用它来检测运算符 operator() 的返回值的类型。

is_odd() 是一个可以像 val() 一样使用的函数。两个函数都返回一个函数对象。调用时,参数将转发给运算符 operator()。对于示例 39.6,这意味着 std::count_if() 仍然计算奇数。

示例 39.7。将独立功能转换为 Phoenix 功能

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
bool is_odd_function(int i) { return i % 2 == 1; }
BOOST_PHOENIX_ADAPT_FUNCTION(bool, is_odd, is_odd_function, 1)
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  using namespace boost::phoenix::placeholders;
  std::cout << std::count_if(v.begin(), v.end(), is_odd(arg1)) << '\n';
}

如果要将独立函数转换为 Phoenix 函数,可以按照示例 39.7 进行操作。您不必像前面的示例中那样定义函数对象。

您可以使用宏 BOOST_PHOENIX_ADAPT_FUNCTION 将独立函数转换为 Phoenix 函数。将返回值的类型、要定义的 Phoenix 函数的名称、独立函数的名称以及参数个数传递给宏。

示例 39.8。 Phoenix 使用 boost::phoenix::bind() 函数

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
bool is_odd(int i) { return i % 2 == 1; }
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  using namespace boost::phoenix;
  using namespace boost::phoenix::placeholders;
  std::cout << std::count_if(v.begin(), v.end(), bind(is_odd, arg1)) << '\n';
}

要将独立函数用作 Phoenix 函数,您还可以使用 boost::phoenix::bind(),如示例 39.8 中所示。 boost::phoenix::bind() 的工作方式类似于 std::bind()。独立函数的名称作为第一个参数传递。所有进一步的参数都被转发到独立功能。

小费
避免使用 boost::phoenix::bind()。创建您自己的 Phoenix 函数。这会导致代码更具可读性。尤其是对于复杂的表达式,处理 boost::phoenix::bind() 的额外细节是没有帮助的。

示例 39.9。任意复杂的 Phoenix 函数

#include <boost/phoenix/phoenix.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
  std::vector<int> v{1, 2, 3, 4, 5};
  using namespace boost::phoenix;
  using namespace boost::phoenix::placeholders;
  int count = 0;
  std::for_each(v.begin(), v.end(), if_(arg1 > 2 && arg1 % 2 == 1)
    [
      ++ref(count)
    ]);
  std::cout << count << '\n';
}

Boost.Phoenix 提供了一些模拟 C++ 关键字的函数对象。例如,您可以使用函数 boost::phoenix::if_()(参见示例 39.9)创建一个函数对象,该对象的行为类似于 if 并测试条件。如果条件为真,则使用 operator[] 传递给函数对象的代码将被执行。当然,该代码也必须基于函数对象。这样,您可以创建复杂的 Phoenix 函数。

示例 39.9 对每个大于 2 的奇数进行增量计数。要对 count 使用增量运算符,请使用 boost::phoenix::ref() 将 count 包装在一个函数对象中。与 boost::phoenix::val() 相比,没有值被复制到函数对象中。 boost::phoenix::ref() 返回的函数对象存储了一个引用——这里是对 count 的引用。

小提示

不要使用 Boost.Phoenix 创建复杂的函数。最好使用 C++11 中的 lambda 函数。虽然 Boost.Phoenix 接近 C++ 语法,但使用 if_ 等关键字或方括号之间的代码块并不一定会提高可读性。

到此这篇关于C++ Boost Phoenix库示例分析使用的文章就介绍到这了,更多相关C++ Boost Phoenix库内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost实现数字与字符串转化详解

    目录 一.引言 二.Boost.LexicalCast 2.1 示例1 2.2 示例2 三.lexical_cast与c/c++提供类似接口的比较 3.1 两者比较 3.2 样例 一.引言 在boost库中,有一个函数Boost.LexicalCast可以将数字和字符串进行双向转换.本文介绍这种用法的案例. 二.Boost.LexicalCast Boost.LexicalCast 提供了一个转换运算符,boost::lexical_cast,它可以将数字从字符串转换为数字类型,例如 int 或

  • C++ Boost Chrono实现计时码表流程详解

    目录 一.Boost.Chrono说明 二.示例代码 一.Boost.Chrono说明 库 Boost.Chrono 提供了多种时钟.例如,您可以获取当前时间,也可以测量流程中经过的时间. Boost.Chrono 的部分内容已添加到 C++11.如果您的开发环境支持 C++11,您可以访问头文件 chrono.xml 中定义的多个时钟.但是,C++11 不支持某些功能,例如用于测量 CPU 时间的时钟.此外,只有 Boost.Chrono 支持用户定义的时间输出格式. 二.示例代码 您可以通过

  • C++ Boost ScopeExit超详细讲解

    目录 一.提要 二.退出作用域(Boost.ScopeExit) 2.1 范例1.UsingBOOST_SCOPE_EXIT 2.2 示例2.Boost.ScopeExit和C++11的lambda函数 2.3 示例3.特点BOOST_SCOPE_EXIT 三.练习 一.提要 资源有很多种,每种都封装一套,还是挺繁琐的!对于比较少使用或者一个程序很可能只会用一次的资源,我们不想封装,在这种情况下用Boost.ScopeExit. 二.退出作用域(Boost.ScopeExit) 库 Boost.

  • C++ Boost Format超详细讲解

    Boost.Format Boost.Format 提供了函数 std::printf() 的替代品. std::printf() 源自 C 标准并允许格式化数据输出.但是,它既不是类型安全的,也不是可扩展的. Boost.Format 提供了一种类型安全且可扩展的替代方案. Boost.Format 提供了一个名为 boost::format 的类,该类在 boost/format.hpp 中定义.与 std::printf() 类似,将包含用于控制格式的特殊字符的字符串传递给 boost::

  • C++ Boost Tokenizer使用详细讲解

    目录 介绍 示例一 示例二 示例三 示例四 示例五 示例六 示例七 介绍 库 Boost.Tokenizer 允许您通过将某些字符解释为分隔符来迭代字符串中的部分表达式.使用 boost::tokenizer 迭代字符串中的部分表达式 示例一 使用 boost::tokenizer 迭代字符串中的部分表达式 #include <boost/tokenizer.hpp> #include <string> #include <iostream> int main() {

  • C++ Boost PointerContainer智能指针详解

    目录 一.提要 二.智能指针Boost.PointerContainer 三.练习 一.提要 在 C++11 中,Boost.PointerContainer是另一个智能指针,一般是用来生成集合数据的,本文阐述这种指针的特点和用法. 二.智能指针Boost.PointerContainer 库 Boost.PointerContainer 提供专门用于管理动态分配对象的容器.例如,在 C++11 中,您可以使用 std::vector<std::unique_ptr<int>> 创

  • C++ Boost StringAlgorithms超详细讲解

    目录 一.提要 二.简化字符串处理的工具和其库 三.应用Boost.StringAlgrithms库 3.1 字符大小写 3.2 删除字符串内子串 3.3 查找字符串内子串 3.4 合并字符串 3.5 子串替换 3.6 字符串修剪 3.7 创立谓词 3.8 比较 3.9 拆分字符串 3.10 查找字符串 练习 一.提要 boost C++对应的字符串对象也有一套标准操作方法.本文介绍库Boost.StringAlgorithms的若干函数和功能示例. 二.简化字符串处理的工具和其库 Boost.

  • C++ Boost Xpressive示例分析使用

    目录 一.综述 二.应用示例 2.1 示例 9.1 2.2 示例 9.2 2.3 示例 9.3 2.4 示例 9.4 一.综述 与 Boost.Regex 一样,Boost.Xpressive 提供了使用正则表达式搜索字符串的函数.然而,Boost.Xpressive 使得将正则表达式写成 C++ 代码而不是字符串成为可能.这使得在编译时检查正则表达式是否有效成为可能. 只有 Boost.Regex 被合并到 C++11 中.标准库不支持将正则表达式编写为 C++ 代码. boost/xpres

  • C++ Boost Phoenix库示例分析使用

    目录 一.说明 二.预先知道Boost.Phoenix 三.示例和代码 一.说明 在函数式编程模型中,函数是对象,与其他对象一样,可以作为参数传递给函数或存储在容器中.有许多支持函数式编程模型的 Boost 库. Boost.Phoenix 是这些库中最广泛.也是最重要的库.它取代了库 Boost.Lambda,它被简要介绍,但只是为了完整性. Boost.Function 提供了一个类,可以轻松定义函数指针,而无需使用源自 C 编程语言的语法. Boost.Bind 是一个适配器,即使实际签名

  • C++ Boost Intrusive库示例精讲

    目录 一.说明 二.示例 一.说明 Boost.Intrusive 是一个特别适合在高性能程序中使用的库.该库提供了创建侵入式容器的工具.这些容器替换了标准库中的已知容器.它们的缺点是它们不能像 std::list 或 std::set 那样容易使用.但它们有以下优点: 侵入式容器不会动态分配内存.对 push_back() 的调用不会导致使用 new 进行动态分配.这是侵入式容器可以提高性能的一个原因. 侵入式容器不会动态分配内存.对 push_bacIntrusive 容器的调用存储原始对象

  • C++ Boost Any示例分析使用

    目录 一.提要 二.Boost.Any示例 一.提要 强类型语言,例如 C++,要求每个变量都有一个特定的类型来定义它可以存储什么样的信息.其他语言,例如 JavaScript,允许开发人员将任何类型的信息存储在变量中.例如,在 JavaScript 中,单个变量可以包含一个字符串,然后是一个数字,然后是一个布尔值. 二.Boost.Any示例 Boost.Any 提供了 boost::any 类,它与 JavaScript 变量一样,可以存储任意类型的信息. 示例 23.1.使用 boost:

  • C++ Boost Foreach超详细分析讲解

    目录 一.说明 二.示例代码 2.1 最简单的代码 2.2 使用BOOST_FOREACH与BOOST_REVERSE_FOREACH 三.BOOST_FOREACH特点和应用范围 四.遍历循环控制 一.说明 Boost.Foreach Boost.Foreach 提供了一个宏来模拟 C++11 中基于范围的 for 循环.您可以使用在 boost/foreach.hpp 中定义的宏 BOOST_FOREACH 来迭代序列而不使用迭代器.如果你的开发环境支持C++11,可以忽略Boost.For

  • C++中的boost::function库简介

    boost::function Boost.Function库用来提供一个对象化的函数指针,通过它可以很容易的将一个函数封装为仿函数. boost::function库可以支持自由函数,函数对象,类成员函数.而且参数个数多达10个.boost::function库利用模板技术来实现.生成的代码有很高的运行效率.首先我们还是以一个例子简单的说明它的用法: #include <iostream> #include <boost/function.hpp> using namespace

  • React Hooks钩子中API的使用示例分析

    目录 hooks是什么 Hooks的作用 使用Hooks组件前后开发模式的对比 Hooks使用策略 为什么要有Hooks useState useEffect使用 useEffect依赖项 使用情景 useMemo使用 useMemo缓存组件方式 useMemo和useEffect的区别 useCallback使用 useContext使用 useRef使用 为什么在函数组件中无法使用ref 如何在类组件中使用ref属性 自定义hooks hooks是什么 hooks理解字面意思就是钩子,是一些

  • Native Memory Tracking追踪区域示例分析

    目录 Compiler Internal Symbol Native Memory Tracking Arena Chunk Unknown Compiler Compiler 就是 JIT 编译器线程在编译 code 时本身所使用的内存. 查看 NMT 详情: [0x0000ffff93e3acc0] Thread::allocate(unsigned long, bool, MemoryType)+0x348 [0x0000ffff9377a498] CompileBroker::make_

  • C++ Boost Flyweight库使用介绍

    目录 一.说明 二.库Boost.Flyweight 炼习 一.说明 以下库用于设计模式. Boost.Flyweight 有助于在程序中使用许多相同的对象并且需要减少内存消耗的情况. Boost.Signals2 使得使用观察者设计模式变得容易.这个库被称为 Boost.Signals2 因为它实现了信号/槽的概念. Boost.MetaStateMachine 使得将状态机从 UML 转移到 C++ 成为可能. 本节内容 66. Boost.Flyweight 67. Boost.Signa

  • C++ STL容器与函数谓词示例分析讲解

    目录 1.C++ vector向量 2.C++ stack 栈 3.C++ queue 队列 4.优先级队列 5.C++ list 6.c++ set 集合 7.C++ map函数 8.C++ multimap容器 9.C++ 谓词 10.C++内置预定义函数 C++ STL(Standard Template Library标准模板库),相当于java的集合模块, STL 有很多的容器. 1.C++ vector向量 (内部:封装动态大小数组作为容器,能够存放任意的动态数组) #include

随机推荐