Search code examples
c++c++11move-semanticslvalueforwarding-reference

Universal reference l-value not copying object


Why these asserts work for the below code? The universal reference should bind to l-value reference run(T& a), and copy an object b from a. However both objects addresses "a" and "b" are the same in the run() function. Tested with C++11/14/17/2a gcc-9.2 and clang++-6.0. What part of the standard says this is valid? did not find anything related.

#include <cassert>
#include <utility>

template <typename T>
void run(T&& a)
{
  T b {std::forward<T>(a)};
  ++b;
  assert(b == a);
  assert(&a == &b);
}

int main()
{
  int value {10};
  run(value); // asserts work, not expected
  // run(std::move(value)); // the asserts don't work as expected
}

Solution

  • However both objects addresses "a" and "b" are the same in the run() function.

    When being passed an lvalue, T is deduced as lvalue-reference, i.e. int&. (int& && collapses to int&, so the type of function parameter a is int&.) Then b is declared as a reference binding to a.

    When being passed an rvalue, T is deduced as int. (So the type of function parameter a is int&&.) Then b is declared as an independent variable copied from a.