模板化函数接受lambda问题



我有一个像这样的模板函数:

template<class RenderableFunc>
void DrawModels(const RenderQueue& renderQueue, RenderableFunc&& preDrawFunc)
{
    // .......
}

像这样调用它:

auto preDrawRenderable = [this](const Renderable& renderable) 
                            {
                                // ...........
                            };
DrawModels<decltype(preDrawRenderable)>(renderQueue, preDrawRenderable);

然而,当与VS2013编译时,我得到这个:

error C2664: 
with
[
RenderableFunc=JonsEngine::OpenGLRenderer::GeometryStage::<lambda_411ef98538bba0cf82404b7a6f008e46>
]
You cannot bind an lvalue to an rvalue reference

为什么会这样?我想上面的电话是合法的,不是吗?

在这种情况下,不需要显式指定类型模板参数RenderableFunc。编译器会推断它,一切都会好起来:

DrawModels(renderQueue, preDrawRenderable);

如果您实际指定它,那么由于preDrawRenderable是一个未加括号的id表达式,您将得到实际的闭包类型为RenderableFunc,这将RenderableFunc&&转换为右值引用。当然,正如编译器告诉您的,您不能将左值preDrawRenderable绑定到右值引用。

当您让编译器推断类型时,适用于T&&形式的参数的特殊规则将被应用,而RenderableFunc实际上被推断为对闭包类型的左值引用。根据引用折叠规则,RenderableFunc&&也是一个左值引用,并且一切正常。如果你真的想指定模板参数,你可以使用

DrawModels<decltype((preDrawRenderable))>(renderQueue, preDrawRenderable);

额外的一对括号将decltype返回的类型更改为左值引用,因为preDrawRenderable是左值引用。引用折叠规则再次应用,一切都像让编译器推断类型一样工作。

最新更新