当前位置: 首页 > 知识库问答 >
问题:

使用lambdas简化容器迭代

司空兴为
2023-03-14
void functionA() {
  // ...........

  auto meshIterator = mMeshes.begin();
  for (const Renderable &renderable : renderQueue) {
    if (renderable.mMesh == INVALID_MESH_ID) {
      JONS_LOG_ERROR(mLogger, "Renderable MeshID is invalid");
      throw std::runtime_error("Renderable MeshID is invalid");
    }

    if (renderable.mMesh < meshIterator->first->mMeshID)
      continue;

    while (renderable.mMesh > meshIterator->first->mMeshID) {
      meshIterator++;
      if (meshIterator == mMeshes.end()) {
        JONS_LOG_ERROR(mLogger, "Renderable MeshID out of range");
        throw std::runtime_error("Renderable MeshID out of range");
      }
    }

    const bool hasDiffuseTexture =
        renderable.mDiffuseTexture != INVALID_TEXTURE_ID;
    const bool hasNormalTexture =
        renderable.mNormalTexture != INVALID_TEXTURE_ID;

    mGeometryProgram.SetUniformData(
        UnifGeometry(renderable.mWVPMatrix, renderable.mWorldMatrix,
                     hasDiffuseTexture, hasNormalTexture,
                     renderable.mTextureTilingFactor));

    if (hasDiffuseTexture)
      BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_DIFFUSE,
                    renderable.mDiffuseTexture, mTextures, mLogger);

    if (hasNormalTexture)
      BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_NORMAL,
                    renderable.mNormalTexture, mTextures, mLogger);

    GLCALL(glBindVertexArray(meshIterator->second));
    GLCALL(glDrawElements(GL_TRIANGLES, meshIterator->first->mIndices,
                          GL_UNSIGNED_INT, 0));
    GLCALL(glBindVertexArray(0));
  }

  // ...........
}

void functionB() {
  //....................

  // both containers are assumed to be sorted by MeshID ascending
  auto meshIterator = mMeshes.begin();
  for (const Renderable &renderable : renderQueue) {
    if (renderable.mMesh == INVALID_MESH_ID) {
      JONS_LOG_ERROR(mLogger, "Renderable MeshID is invalid");
      throw std::runtime_error("Renderable MeshID is invalid");
    }

    if (renderable.mMesh < meshIterator->first->mMeshID)
      continue;

    while (renderable.mMesh > meshIterator->first->mMeshID) {
      meshIterator++;
      if (meshIterator == mMeshes.end()) {
        JONS_LOG_ERROR(mLogger, "Renderable MeshID out of range");
        throw std::runtime_error("Renderable MeshID out of range");
      }
    }

    const Mat4 wvp = lightVP * renderable.mWorldMatrix;
    mNullProgram.SetUniformData(UnifNull(wvp));

    GLCALL(glBindVertexArray(meshIterator->second));
    GLCALL(glDrawElements(GL_TRIANGLES, meshIterator->first->mIndices,
                          GL_UNSIGNED_INT, 0));
    GLCALL(glBindVertexArray(0));
  }

  // ...............
}
void DrawModels(const std::function<
    void(const Renderable &renderable)> &preDrawFunc) {
  // both containers are assumed to be sorted by MeshID ascending
  auto meshIterator = mMeshes.begin();
  for (const Renderable &renderable : renderQueue) {
    if (renderable.mMesh == INVALID_MESH_ID) {
      JONS_LOG_ERROR(mLogger, "Renderable MeshID is invalid");
      throw std::runtime_error("Renderable MeshID is invalid");
    }

    if (renderable.mMesh < meshIterator->first->mMeshID)
      continue;

    while (renderable.mMesh > meshIterator->first->mMeshID) {
      meshIterator++;
      if (meshIterator == mMeshes.end()) {
        JONS_LOG_ERROR(mLogger, "Renderable MeshID out of range");
        throw std::runtime_error("Renderable MeshID out of range");
      }
    }

    preDrawFunc(renderable);

    GLCALL(glBindVertexArray(meshIterator->second));
    GLCALL(glDrawElements(GL_TRIANGLES, meshIterator->first->mIndices,
                          GL_UNSIGNED_INT, 0));
    GLCALL(glBindVertexArray(0));
  }
}
void functionD() {
  auto preDrawRenderable = [&](const Renderable &renderable) {
    const bool hasDiffuseTexture =
        renderable.mDiffuseTexture != INVALID_TEXTURE_ID;
    const bool hasNormalTexture =
        renderable.mNormalTexture != INVALID_TEXTURE_ID;

    mGeometryProgram.SetUniformData(
        UnifGeometry(renderable.mWVPMatrix, renderable.mWorldMatrix,
                     hasDiffuseTexture, hasNormalTexture,
                     renderable.mTextureTilingFactor));

    if (hasDiffuseTexture)
      BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_DIFFUSE,
                    renderable.mDiffuseTexture, mTextures, mLogger);

    if (hasNormalTexture)
      BindTexture2D(OpenGLTexture::TEXTURE_UNIT_GEOMETRY_NORMAL,
                    renderable.mNormalTexture, mTextures, mLogger);
  };

  DrawModels(preDrawRenderable);
}

void functionE() {
  auto preDrawRenderable = [&](const Renderable &renderable) {
    const Mat4 wvp = lightVP * renderable.mWorldMatrix;
    mNullProgram.SetUniformData(UnifNull(wvp));
  };

  DrawModels(preDrawRenderable);
}

1)functionD和functionE每秒都需要运行60-100次。使用lambda和std::function是否会对性能造成重大影响?例如,是否存在隐藏的动态内存分配调用或虚拟查找,或者其他可能会影响性能的东西?我不知道使用lambdas和std::function的开销。

2)有没有比我天真的解决方案更好/更快/更干净的替代方案?

共有1个答案

沈高峻
2023-03-14
void DrawModels(const std::function< void(const Renderable &renderable)> &preDrawFunc)

与其这样做,不如这样做:

template<class RenderableFunc>
void DrawModels(RenderableFunc&& preDrawFunc)

并保持身体不变。将其放置在您正在替换的两个函数都可以看到的位置。

现在编译器有一个简单的优化问题来内联您的lambda。

 类似资料:
  • 我们用Android中非常典型的例子去解释它是怎么工作的:View.setOnClickListener()方法。如果我们想用Java的方式去增加点击事件的回调,我首先要编写一个OnClickListener接口: public interface OnClickListener { void onClick(View v); } 然后我们要编写一个匿名内部类去实现这个接口: view.s

  • 假设您希望对迭代器的元素进行流式处理;让我们使用一个的具体示例,它实现了。 给定,比方说: 在给定的情况下,JDK中是否有一个工厂方法返回?

  • 我有一个比较器,它检查字符串是否为空,并返回-1。如果它们不是null,则进行比较。我想用lambda函数实现这个。 以下是代码: 我知道如何使用lambdas返回一个简单的比较器。我对如何实现上述代码感到困惑。

  • 最常见的类型包括容器类(container class),也称集合类(collection class),是保存一组对象集合的类。容器类通常提供插入、删除、查找、排序和测试类成员项目等操作。数组、堆栈、队列、树和链表都是容器类,第4章介绍了数组,第11章和20章将介绍其他数据结构。 容器类经常与迭代对象(iterator object;或简称迭代器,aerator)相关联。迭代对象返回集合中的下一

  • 一个自动点唱机只有一首歌恐怕不会太流行,所以我们需要建立一个歌曲目录和一个等待播放的列表。这都是容器的例子,一个包含若干个对其它对象引用的对象。 目录和播放列表都有类似的操作,增加歌曲,删除歌曲,返回歌曲列表等等。播放列表可能还需要别的方法,比如插入广告,记录累计播放时间等,我们将在后面考率这些问题。现在,我们需要建立一个SongList类,以便在目录和播放列表中使用。 容器 在开始实现之前,我们

  • 我有一个现有的 Azure 函数,用于解压缩文件并将每个文件添加为 blob。 我现在想迭代这些文件并执行它们(它们是SQL文件)。我不想触发一个基于blob创建的函数,而是在一个函数中运行它们。 在一个函数中,我如何在一个容器中迭代一个blobs列表并获取它们的内容? 谢谢

  • 本文向大家介绍python迭代器实例简析,包括了python迭代器实例简析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python迭代器的简单用法,分享给大家供大家参考。具体分析如下: 生成器表达式是用来生成函数调用时序列参数的一种迭代器写法 生成器对象可以遍历或转化为列表(或元组等数据结构),但不能切片(slicing)。当函数的唯一的实参是可迭代序列时,便可以去掉生成器表达式两端>

  • 本文向大家介绍简述 生成器、迭代器、可迭代对象 以及应用场景?相关面试题,主要包含被问及简述 生成器、迭代器、可迭代对象 以及应用场景?时的应答技巧和注意事项,需要的朋友参考一下 迭代器 含有iter和next方法 (包含next方法的可迭代对象就是迭代器) 生成器: 包括含有yield这个关键字,生成器也是迭代器,调动next把函数变成迭代器。     可迭代对象 一个类内部实现iter方法且返