¿Puede devolver una variable local por valor en C ++ 11/14, lo que da como resultado que el valor de retorno se construya con rvalue cuando no se trata de copiar / mover?

Sé que en la siguiente situación el comstackdor es libre de moverse: construye el valor de retorno de makeA (pero también puede eludir la copia o moverlo por completo):

 struct A { A(A&); A(A&&); }; A makeA() { A localA; return localA; } 

Lo que me pregunto es si el comstackdor puede construir un objeto de tipo A partir de un objeto local de tipo B mediante una referencia de valor real si se está construyendo en la statement de devolución. En otras palabras, en el siguiente ejemplo, ¿se permite al comstackdor seleccionar el constructor 4 de A para el valor de retorno?

 struct B { }; struct A { A(A&); // (1) A(A&&); // (2) A(B&); // (3) A(B&&); // (4) }; A makeA() { B localB; return localB; } 

Pregunto esto porque me parece que la misma lógica que permite que un objeto local de tipo A sea ​​tratado como un valor r en la statement de retorno también debería permitir que un local de cualquier tipo sea tratado como un valor r, pero no puedo encontrarlo. cualquier ejemplo o pregunta de esta naturaleza.

La regla para esta situación cambió entre 2011 y 2014. El comstackdor ahora debe tratar localB como un valor r.

La regla aplicable para declaraciones de return se encuentra en §12.8 [class.copy] / p32, que se lee en C ++ 14 (citando N3936, énfasis mío):

Cuando se cumplen los criterios para elisión de una operación de copiar / mover, pero no para una statement de excepción , y el objeto que se va a copiar se designa con un valor l, o cuando la expresión en una statement de retorno es un id (posiblemente entre paréntesis) expresión que nombra un objeto con duración de almacenamiento automática declarada en el cuerpo o cláusula de statement-parámetro de la función de inclusión más interna o expresión lambda , la resolución de sobrecarga para seleccionar el constructor para la copia se realiza primero como si el objeto fuera designado por un valor r . Si la primera resolución de sobrecarga falla o no se realizó, o si el tipo del primer parámetro del constructor seleccionado no es una referencia rvalue al tipo del objeto (posiblemente cv-qualified), la resolución de sobrecarga se realiza nuevamente, considerando el objeto como un lvalue

La cláusula en negrita fue agregada por CWG número 1579 , expresamente para requerir que el constructor de movimiento de conversión A::A(B&&) sea ​​llamado aquí. Esto se implementa en GCC 5 y Clang 3.9.

Ya en 2011, esta regla de “probar primero validar” estaba estrechamente relacionada con los criterios para la elisión de copia (citando N3337):

Cuando se cumplen o se cumplirían los criterios para elisión de una operación de copia, salvo por el hecho de que el objeto fuente es un parámetro de función, y el objeto que se va a copiar está designado por un lvalue, la resolución de sobrecarga para seleccionar el constructor para la copia es primero se realizó como si el objeto fuera designado por un valor r.

Como la elisión de copia necesariamente requiere que los dos tengan el mismo tipo, este párrafo no se aplicaba, y el comstackdor tenía que usar el constructor A::A(B&) .

Tenga en cuenta que como CWG 1579 se considera un DR contra C ++ 11, los comstackdores deberían implementar su resolución incluso en el modo C ++ 11.