我有这样的模板化功能:

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上面的电话是合法的吗?

最佳答案

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

DrawModels(renderQueue, preDrawRenderable);

如果您实际指定它,则由于preDrawRenderable是未括号的id表达式,您将获得实际的闭合类型为RenderableFunc,这会将RenderableFunc&&转换为右值引用。当然,正如编译器告诉您的那样,您不能将左值preDrawRenderable绑定(bind)到右值引用。

当您离开编译器推断类型时,适用于T&&形式参数的特殊规则将适用,并且RenderableFunc实际上被推导为对闭包类型的左值引用。根据引用折叠规则,RenderableFunc&&也是左值引用,并且一切正常。如果您确实要指定template参数,则可以执行
DrawModels<decltype((preDrawRenderable))>(renderQueue, preDrawRenderable);

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

09-05 23:17