1

So, I created a project and copied this tutorial in it. When I tried to run it, it gave me this error: 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));

I searched a lot but i found nothing that fits in the context. What can I do to fix it?

  • Whatever comes out of `CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get()` is probably too short lived for a pointer to it to have any value. The object would be gone and the pointer invalid before it could be used or time would be wasted updating a value that would be gone before it could be used.. – user4581301 Dec 15 '20 at 23:39
  • 1
    Handy reading: [What are rvalues, lvalues, xvalues, glvalues, and prvalues?](https://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues) – user4581301 Dec 15 '20 at 23:42
  • 1
    This code looks like it is creating a temporary `Transition` object. It is illegal to take the address of a temporary with the `&` address-of operator. – Remy Lebeau Dec 15 '20 at 23:48
  • 1
    Just checked. `Transition` returns a `CD3DX12_RESOURCE_BARRIER` by value. That makes it a prvalue, and you can't take the address of a prvalue. What you can do is make two steps, one calls `Transition` and stores the returned value into a variable. Now you have an `lvalue` you can take the address of an use in the call to `ResourceBarrier`. Whether or not this is a good idea needs a bit more context. A local variable might not have a long enough life if `ResourceBarrier` stores that pointer and tries to use it after the current function exists. – user4581301 Dec 15 '20 at 23:50

2 Answers2

5

This is essentially the same build error reported under Issue #652 Error building D3D12MeshShaders (on VS 16.8.0 Preview 3.0) in the DirectX-Graphics-Samples repo.

I'm getting error C2102: '&' requires l-value on many of the lines. Usually it's when a CD3DX12 constructor is directly used with an &, for example [...]

The issue is still open, with an interim workaround given in a comment:

The use of an address of an r-value like this [...] is non-conforming code.

Visual C++ emits a warning C4238 here with /W4 warning level 4, but most VC projects default to level 3 including these samples. [...] Looks like the latest Visual C++ updates for /permissive- have upgraded this to an error.

You can work around this issue for now by disabling /permissive- by changing "Conformance Mode" to "No" in the C/C++ -> Language project settings.

dxiv
  • 15,185
  • 2
  • 21
  • 41
  • 1
    The problem is that pattern is actually not conformant. The fix is to use: ``auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);`` then ``m_commandList->ResourceBarrier(1, &barrier);`` – Chuck Walbourn Dec 16 '20 at 22:26
  • @ChuckWalbourn Right, as duly noted. The `/permissive` hack is just that, a quick workaround to get the samples to compile without more extensive code changes, not limited to that one occurrence. – dxiv Dec 16 '20 at 22:45
  • 1
    For a long time Visual C++ let you do this without any complaint at Warning 3, so the DirectX 12 official samples and doc snippets had this pattern all over the place. I noticed it because we use Warning 4 for the Xbox samples, I use `/WX` for my GitHub projects, and clang/LLVM also emits a warning. With VS 2019 (16.8) when using ``/permissive-``, Visual C++ now emits this error C2102. The official samples are being cleaned up to stop using this pattern. – Chuck Walbourn Dec 28 '20 at 20:00
1

The problem is that you are trying to get and than pass the address of an rvalue (specifically a prvalue).

And while that's fine from a lifetime perspective (no reference or pointer to the rvalue escapes the full statement in this case), the language does not know and does not try to find out.

I suggest you add keep() for the reverse to std::move():

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

Used like:

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

Just remember that you are going against the grain, and thus any misuse is your own fault.

Deduplicator
  • 41,806
  • 6
  • 61
  • 104