【问题标题】:How can I fix "& requires l-value" [closed]如何修复“& 需要左值”[关闭]
【发布时间】:2021-03-26 15:22:17
【问题描述】:

所以,我创建了一个项目并将this tutorial 复制到其中。当我尝试运行它时,它给了我这个错误:C2102 & requires l-value at

m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

我搜索了很多,但没有找到适合上下文的内容。我能做些什么来解决它?

【问题讨论】:

  • CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get() 产生的任何东西都可能寿命太短,以至于指向它的指针没有任何价值。对象会消失,并且指针在可以使用之前无效,否则会浪费时间来更新在使用之前会消失的值..
  • 这段代码看起来像是在创建一个临时的Transition 对象。使用&address-of 运算符获取临时地址是非法的。
  • 刚刚检查过。 Transition 按值返回 CD3DX12_RESOURCE_BARRIER。这使它成为纯右值,并且您不能获取纯右值的地址。您可以做两步,第一步调用Transition 并将返回值存储到变量中。现在您有一个lvalue,您可以在调用ResourceBarrier 时获取一个使用地址。这是否是一个好主意需要更多的上下文。如果ResourceBarrier 存储该指针并在当前函数存在后尝试使用它,则局部变量可能没有足够长的寿命。

标签: c++ visual-studio-2019 directx-12


【解决方案1】:

这与Issue #652 下报告的构建错误基本相同Error building D3D12MeshShaders (on VS 16.8.0 Preview 3.0)DirectX-Graphics-Samples repo 中。

我收到错误 C2102:'&' 在许多行上都需要左值。通常是当 CD3DX12 构造函数直接与 & 一起使用时,例如 [...]

问题仍然存在,评论中给出了临时解决方法:

像这样 [...] 使用 r 值的地址是不符合标准的代码。

Visual C++ 在此处发出警告 C4238 和 /W4 警告级别 4,但大多数 VC 项目默认为级别 3,包括这些示例。 [...] /permissive 的最新 Visual C++ 更新似乎已将此升级为错误。

您现在可以通过在 C/C++ -> 语言项目设置中将“一致性模式”更改为“否”来禁用 /permissive- 来解决此问题。

【讨论】:

  • 问题是模式实际上不符合。解决方法是使用:auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); 然后m_commandList->ResourceBarrier(1, &barrier);
  • @ChuckWalbourn 正确,正如适当指出的那样。 /permissive hack 就是这样一种快速解决方法,无需更广泛的代码更改即可编译示例,不仅限于一次。
  • 很长一段时间以来,Visual C++ 让您在警告 3 处毫无怨言地做到这一点,因此 DirectX 12 官方示例和 doc sn-ps 到处都有这种模式。我注意到它是因为我们对 Xbox 示例使用警告 4,我对我的 GitHub 项目使用 /WX,并且 clang/LLVM 也会发出警告。在 VS 2019 (16.8) 中使用 /permissive- 时,Visual C++ 现在会发出此错误 C2102。正在清理官方样本以停止使用此模式。
【解决方案2】:

问题是您试图获取并传递右值(特别是纯右值)的地址。

虽然从生命周期的角度来看这很好(没有引用或指向右值的指针转义完整的语句在这种情况下),但语言不知道也不会尝试找出。

我建议你在std::move()后面加keep()

template <class T>
constexpr auto& keep(T&& x) noexcept {
    return x;
}

像这样使用:

m_commandList->ResourceBarrier(1,
    &keep(CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get()),
    D3D12_RESOURCE_STATE_PRESENT,
    D3D12_RESOURCE_STATE_RENDER_TARGET));

请记住,您违反了规定,因此任何滥用都是您自己的错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 2022-10-13
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多