2012-04-14 10 views
8

¿Un tipo de devolución como este representa algo significativo en C++ 11?semántica del tipo de retorno de referencia r-valor?

template <typename R> 
R&& grabStuff(); 

T instance = grabStuff<T>(); 

espero que grabStuff debe lanzar un error en tiempo de compilación si R no tiene un constructor movimiento, ya que esto parecería no permitir que el tipo de retorno de utilizar un constructor de copia

Respuesta

5

Como siempre, al devolver referencias, debe devolver una referencia a algo que aún está vivo después de que la función retorna. Cómo lo haces depende de ti. Ejemplo:

T global_thing; 

T && get() { return std::move(global_thing); } 

struct Foo { Foo(T &&); /* ... */ }; 

int main() 
{ 
    global_thing.reset(); 
    Foo a(get()); 
    global_thing.reset(); 
    Foo b(get()); 
} 

El ejemplo más típico para devolver una referencia rvalue es std::move en sí, sin embargo, que devuelve una referencia a lo que pase en (y por lo tanto es la responsabilidad de la persona que llama para proporcionar una entrada válida) .

+0

El objeto no necesita ser un objeto global. Un objeto local de gestión de recursos también es un ejemplo (es decir, tal vez: D). – Nawaz

+0

@Kerrek, entonces ¿qué estás diciendo es que esta función solo debe llamarse en temporarios? no se puede asignar el resultado de 'get()' en su ejemplo a una referencia normal de 'Foo &'? – lurscher

+0

@Nawaz: Sí, sí, como dije, depende de usted ... Solo quería dar un ejemplo que sea * not * 'std :: move'. –

1

Puede ser significativa según lo que quieras hacer con él y cómo has implementado la función.

De hecho, std::move tipo de retorno es T&& (referencia rvalue) que es significativo, ya que define el propósito mismo de la existencia de std::move en la biblioteca de C++ 11:

+0

'std :: move' es la instancia significativa ** ** de un tipo de devolución de referencia rvalue. Nunca sería significativo en el código de usuario. – ildjarn

+0

@ildjarn: No puedo afirmar que * "** nunca ** sería significativo en el código de usuario" *. Solo digo que la referencia-valor-valor como tipo de retorno puede ser significativa. – Nawaz

+0

Lo estoy afirmando. ; -] En _code_usuario (a menos que ese código de usuario esté duplicando 'std :: move' por alguna razón impar), un tipo de devolución de referencia rvalue no puede hacer nada semánticamente significativo. – ildjarn

1

Si el tipo de retorno de una función es una referencia rvalue, entonces el resultado de la llamada a la función es un valor x; si el tipo de devolución no es de referencia, el resultado de la llamada a la función es un valor pr.

Tanto xvalue como prvalue son valores r, existen algunas pequeñas diferencias entre ellos, más como diferencias entre referencia y no referencia. Por ejemplo, un valor x puede tener un tipo incompleto, mientras que un prvalue generalmente tendrá un tipo completo o tipo vacío. Cuando se aplica typeid a un valor x cuyo tipo es un tipo de clase polimórfica, el resultado se refiere al tipo dinámico; y para prvalue, el resultado se refiere al tipo estático.

Para su declaración declaración T instance = grabStuff<T>();, si T es un tipo de clase, creo que no hay diferencia entre xvalue y prvalue en este contexto.

El inicializador es un valor r, por lo que el compilador prefiere un constructor de movimiento. Pero si no se declara ningún constructor de movimiento y se declara un constructor de copia con el parámetro de referencia const, entonces se elegirá este constructor de copia y no se producirá ningún error. No sé por qué quieres que esto sea un error. Si esto es un error, cualquier código antiguo será incorrecto cuando copie-inicialice algún objeto de un valor r.

Cuestiones relacionadas