【问题标题】:Boost Metafunction class higher order functionBoost Metafunction 类高阶函数
【发布时间】:2012-05-02 18:58:54
【问题描述】:

元函数类与占位符和高阶函数有什么区别?

【问题讨论】:

    标签: c++ boost functional-programming c++11 boost-mpl


    【解决方案1】:

    Boost 为元函数和高阶函数提供了特性,但这些概念并不特定于 Boost。

    术语“元函数”描述了一种模板元编程技术,用于使用模板特化来允许编译器在编译时根据其模板参数做出决定。

    通常,元函数可能看起来像这样

    template<bool B>
    struct my_metafunction
    {
        enum { value = 1 };
    };
    
    template<>
    struct my_metafunction<false>
    {
        enum { value = 0 };
    };
    

    当使用my_metafunction 时,my_metafunction&lt;B&gt;::value 的确切值将取决于 B 的值(即my_metafunction&lt;true&gt;::value 将不同于my_metafunction&lt;false&gt;::value)。如果您不熟悉模板元编程,那么您可能想知道为什么这很有用 - 而现实情况是,它通常只对编写大量使用模板和编译时决策的库的人有用。 (模板元编程是一个完全不同的范式!)


    另一方面,“高阶函数”描述了一种函数式编程技术,它允许您将函数作为函数参数传递。这在标准 C++ 中使用标准 &lt;algorithm&gt; 库与标准容器一起使用更容易表达。

    例如,C++ 包含一个名为 transform 的高阶函数 - 它的目的是遍历容器中的每个元素(例如向量、字符串、列表、映射、数组等)并执行转换每个元素。

    std::string str = "Hello, World";
    std::transform(str.begin(),
                   str.end(),
                   str.begin(),
                   std::toupper); // Note - toupper is a function!
    
    std::cout << str << std::endl;
    

    所执行的转换取决于其最终参数std::toupper。 std::toupper 的目的是接受一个(字符)值并返回该值的大写版本。 std::transform 为 str.begin()str.end() 之间的每个元素获取 toupper 的结果(在本例中,结果被放回 str 中)

    标准库中还有很多其他高阶函数示例 - std::find_ifstd::sortstd::count_if 等等。 C++ 中的高阶函数通常可以接受任何类型的可调用对象,包括函数、lambda 或函数对象。
    传递的可调用对象通常被称为 [i]predicates[/i] (虽然我不完全确定这是否是术语“predicate”的正确用法)


    Boost 占位符是函数式编程另一个方面的一部分,称为 currying - 它允许您在调用函数之前将参数“绑定”到函数。 (在 Boost 的世界里,currying 的结果是一个函数对象,它通常被传递给一个高阶函数)。

    Currying 旨在通过重用现有的可调用对象/谓词并在使用它们之前具体设置它们的一些参数来替代编写您自己的自定义专用可调用对象。

    例如,您可以使用高阶函数find_if 在字符串中搜索“大于 q”的第一个字符。 C++ 标准库包含一个名为 greater_equals 的可调用对象,但它需要 find_if 使用的第二个参数(“大于和等于 **to what??”)

    不用currying,你可以写一个函数(暂时忽略所有的大小写敏感),比如

    bool greater_than_or_equals_to_q(char c)
    {
        return c >= 'Q';
    }
    

    使用currying,您可以将字符'Q'“绑定”到greater_equals函数,以创建一个只接受单个参数的谓词,并表示一个谓词在其参数“大于或等于Q”时产生真”。

    std::bind( std::greater_equal<char>(), 
               std::placeholders::_1, 
               'Q' );
    

    所以,使用大写字符串:

    std::string str = "HELLO WORLD";
    auto gt_eq_Q = std::bind( std::greater_equal<char>(), 
                              std::placeholders::_1, 
                              'Q' );
    
    auto iter = std::find_if( str.begin(), str.end(), gt_eq_Q );
    std::cout << *iter << std::endl;
    

    正如预期的那样,“HELLO WORLD”中大于或等于“Q”的第一个字符恰好是“W”

    W
    

    【讨论】:

    • 可能是 OP 想知道的错误占位符。 Boost.MPL 具有高阶元函数(尽管 OP 确实提到了函数),例如 less&lt;_1, _2&gt;Relevant docs.
    • “谓词”是对某个(或多个对象)的条件求值的函数,返回条件是否为真。因此,高阶函数将谓词函数作为参数是相当常见的(例如,返回集合中满足某些条件的所有元素的过滤器函数将使用函数来测试条件,因此您不必重写每个可能条件的过滤函数)。因此,谓词基本上是您传递给高阶函数的特定种类;总是称它们为谓词是不正确的。
    【解决方案2】:

    详细解释请看

    1. http://www.artima.com/cppsource/metafunctions.html
    2. http://www.mywikinet.com/mpl/paper/mpl_paper.pdf

    原则上,元函数是:

    • 所有参数都是类型的类模板
    • 具有可公开访问类型type 的类

    例如:

    template <bool, class L, class R>
    struct IF
    {
      typedef R type; 
    };
    
    template <class L, class R>
    struct IF<true, L, R>
    {
      typedef L type; 
    };
    

    对另一个函数进行操作的函数称为高阶函数。因此,高阶元函数是接受其他元函数作为参数并在计算过程中使用它们的元函数。这在概念上类似于函数在运行时接受指向另一个函数或函数对象的指针作为参数。唯一的区别是元函数仅在编译时存在。 boost::mpl::transform 就是这种高阶元函数的一个例子。

    【讨论】:

      猜你喜欢
      • 2012-10-25
      • 1970-01-01
      • 2020-02-16
      • 2016-05-07
      • 2020-05-17
      相关资源
      最近更新 更多