模板函数接受lambda问题

时间:2014-06-15 15:41:52

标签: c++ c++11 lambda visual-studio-2013

我有这样的模板化函数:

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

这是为什么? Afaik上面的呼吁是合法的吗?

1 个答案:

答案 0 :(得分:2)

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

DrawModels(renderQueue, preDrawRenderable);

如果您实际指定了它,那么因为preDrawRenderable是一个未加密码的 id-expression ,您将获得RenderableFunc的实际闭包类型,将RenderableFunc&&变为右值参考。当然,正如编译器告诉您的那样,您无法将左值preDrawRenderable绑定到右值引用。

当您离开编译器以推断类型时,适用于T&&形式的参数的特殊规则适用,RenderableFunc实际上被推断为左值对闭包类型的引用。通过引用折叠规则,RenderableFunc&&也是左值引用,一切正常。如果您确实要指定模板参数,可以执行

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

额外的括号对将decltype返回的类型更改为左值引用,因为preDrawRenderable是左值。同样,引用折叠规则也适用,并且一切都与编译器推导出类型一样。