gpt4 book ai didi

c++ - 使用 lambda 简化容器迭代

转载 作者:行者123 更新时间:2023-11-30 00:50:40 27 4
gpt4 key购买 nike

我有两个函数,functionA 和 functionB,它们都遍历容器 (std::vector) 并执行一些工作:

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));
}
}

我认为提供的 std::function 可用于根据调用者执行一些任意工作,如下所示:

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 会导致任何显着的性能损失吗?例如,是否有任何隐藏的动态内存分配调用或虚拟查找或诸如此类可能会降低性能的东西?我不知道使用 lambda 和 std::function 的开销。

2) 是否有比我天真的解决方案更好/更快/更清洁的替代方案?

最佳答案

void DrawModels(const std::function< void(const Renderable &renderable)> &preDrawFunc)

取而代之的是,这样做:

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

并保持正文不变。将它放在您要替换的两个函数都可以看到的地方。

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

std::function 是一个类型删除对象,它的魔法会混淆当前一代的优化器。它不是 lambda 的类型,它是一种可以将任何 lambda 或函数指针或可调用对象转换为内部对象并将其存储以供以后执行的类型。

原始 lambda 是编译器生成的函数对象,带有捕获的变量和非虚拟 operaror()。它的重量要轻得多。

关于c++ - 使用 lambda 简化容器迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24219620/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com