【问题标题】:How does STL algorithm work independent of Iterator type?STL 算法如何独立于迭代器类型工作?
【发布时间】:2009-06-20 12:29:24
【问题描述】:

STL 算法如何独立于迭代器类型工作?

【问题讨论】:

    标签: c++ algorithm stl iterator


    【解决方案1】:

    真的,他们只是工作。它们使用模板的一些非常基本的属性,有时称为静态多态性。如果你熟悉这个术语,它本质上是一种鸭式打字。 (如果它长得像鸭子,叫起来像鸭子,那一定是鸭子)

    诀窍很简单。这是一个非常简单的例子:

    template <typename T>
    void say_hello(const T& t) {
      t.hello();
    }
    

    say_hello 函数不关心它的参数是哪种类型。它不必从接口派生或对它是什么做出任何其他类型的“承诺”。重要的是类型 在这种情况下有效。我们对类型所做的只是调用它的hello 函数。这意味着此代码将为具有hello 成员函数的任何类型编译。

    STL 算法的工作原理类似。这是std::for_each的简单实现:

    template <typename iter_type, typename func_type>
    void for_each(iter_type first, iter_type last, func_type f){
      for (iter_type cur = first; cur != last; ++cur) {
        f(*cur);
      }
    }
    

    只要模板类型符合对它们的要求,此代码就会编译; iter_type 必须具有预增量 ++ 运算符。它必须有一个复制构造函数,它必须有 != 运算符,它必须有 *-dereference-operator。

    func_type 必须实现函数调用运算符,接受与通过取消引用 iter_type 类型的对象获得的相同类型的参数。如果我使用满足这些要求的类型调用for_each,代码将编译。 iter_type 可以是满足这些要求的任何类型。代码中没有任何内容说“这适用于向量迭代器、列表迭代器和映射迭代器”。但只要向量、列表或映射迭代器实现我们使用的运算符,它就可以工作。

    【讨论】:

    • 你的意思是 ++-increment 运算符?
    • 哦。其实我的意思是写预增量。固定的。 :)
    【解决方案2】:

    STL 算法是模板函数,这意味着它们可以被任何类型调用。

    当调用具有特定类型的函数时,编译器会尝试编译该特定类型的函数实例并报告任何编译错误(缺少方法、类型检查错误等)

    对于 STL 算法,只要使用的类型表现得像一个迭代器(支持 ++,取消引用),它就可以工作。这就是为什么这些算法也适用于本机指针的原因,因为它们支持与迭代器相同类型的操作(这就是它们最初的设计方式)。

    【讨论】:

      【解决方案3】:

      【讨论】:

      • 每个迭代器都派生自一个通用接口吗?
      • 不,它不使用继承,或者“通常”称为多态性。模板允许它有时称为“静态多态性”,这是 STL 所依赖的。但它与继承、接口或虚函数无关。
      • 这个答案是正确的。投反对票的人应该撤回他们的投票,因为他们需要阅读更多内容。
      • 我们称之为Duck typing + 泛型专业化
      【解决方案4】:

      任何 STL 算法都是由编译器为您使用的每个迭代器类型自动生成的。

      它被称为 C++ 模板或静态多态。

      【讨论】:

        【解决方案5】:

        每个 STL 算法都是一个模板函数,它以迭代器类型作为其模板参数。

        【讨论】:

          【解决方案6】:

          并非所有 STL 容器/迭代器算法都具有这种独立性。这样做的称为通用算法,但这些通常仅称为 STL 算法。

          只有使用迭代器才能:

          • 检查序列,以便您可以执行查找、计数、for_each 等操作……
          • 更改迭代器引用的值,以便您可以执行变换、复制、旋转、交换、替换等操作……
          • 对迭代器的值重新排序,以便您执行排序、合并、nth_element 等操作。

          一些非泛型算法可以分为 2 个阶段,一个 STL 泛型部分和一个容器相关部分。因此,为了销毁向量中所有大于 7 的值,我们可以执行 remove_if(仅对元素进行排序的通用部分),然后执行擦除(销毁值的非通用部分)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-12-07
            • 2010-10-25
            • 2018-06-11
            • 1970-01-01
            • 1970-01-01
            • 2011-01-19
            • 1970-01-01
            相关资源
            最近更新 更多