Dada GMan's función de utilidad auto_cast
deliciosamente mal inventado here, he estado tratando de averiguar por qué no compila para mí cuando estoy tratando de auto_cast
de un valor de lado derecho (en MSVC 10.0).C++ 0x rvalue argumento de plantilla de referencia deducción
Aquí está el código que estoy usando:
template <typename T>
class auto_cast_wrapper : boost::noncopyable
{
public:
template <typename R>
friend auto_cast_wrapper<R> auto_cast(R&& pX);
template <typename U>
operator U() const
{
return static_cast<U>(std::forward<T>(mX));
}
private:
//error C2440: 'initializing': cannot convert from 'float' to 'float &&'
auto_cast_wrapper(T&& pX) : mX(pX) { }
T&& mX;
};
template <typename R>
auto_cast_wrapper<R> auto_cast(R&& pX)
{
return auto_cast_wrapper<R>(std::forward<R>(pX));
}
int main()
{
int c = auto_cast(5.0f); // from an rvalue
}
A lo mejor de mi capacidad he tratado de seguir la referencia C++ 0x colapso de las reglas y las reglas de deducción de argumento de plantilla descrito here, y por lo que puedo decir, el código dado arriba debería funcionar.
Recordemos que en la pre-0x C++, no se le permite tomar una referencia a una referencia: algo así como un & & provoca un error de compilación. C++ 0x, por el contrario, introduce las siguientes reglas colapso de referencia:
- A & & se convierte en un &
- A & & & se convierte en un &
- A & & & se convierte en un &
- A & & & & se convierte en un & &
La segunda regla es una regla especial deducción argumento de plantilla para plantillas de función que tienen un argumento por referencia rvalue a un argumento de plantilla:
template<typename T> void foo(T&&);
En este caso, se aplican las siguientes reglas :
- Cuando foo se llama en una lvalue de tipo a, entonces T se resuelve en un & y por lo tanto, por el refere A pesar de las reglas de colapso anteriores, el tipo de argumento se convierte efectivamente en A &.
- Cuando se invoca foo en un valor r de tipo A, entonces T se resuelve en A, y de ahí que el tipo de argumento se convierta en A & &.
Ahora, cuando el cursor sobre la llamada a auto_cast(5.0f)
, la información sobre herramientas muestra correctamente su valor de retorno como auto_cast_wrapper<float>
. Este sentido de que el compilador ha seguido correctamente la regla 2:
Cuando se llama foo en un valor p de tipo A, entonces T se resuelve a A.
lo tanto, ya tenemos un auto_cast_wrapper<float>
, el constructor debe instanciar para tomar un float&&
. Pero el mensaje de error parece implicar que crea un valor de float
por valor.
Este es el mensaje de error completo, demostrando una vez más que T = flote correctamente sin embargo, el T & & parámetro se convierte en T?
main.cpp(17): error C2440: 'initializing' : cannot convert from 'float' to 'float &&' You cannot bind an lvalue to an rvalue reference main.cpp(17) : while compiling class template member function 'auto_cast_wrapper<T>::auto_cast_wrapper(T &&)' with [ T=float ] main.cpp(33) : see reference to class template instantiation 'auto_cast_wrapper<T>' being compiled with [ T=float ]
¿Alguna idea?
¿Alguna posibilidad de que puedas enfocar un poco la pregunta? En lugar de poner ediciones en la parte inferior como párrafos separados, edítelos * en * la pregunta en sí. Como lector no necesito saber el orden en el que adjuntó las cosas a la pregunta, solo quiero leer la mejor versión posible de la pregunta. Y si desea publicar la respuesta usted mismo, hágalo como una respuesta real, no como un párrafo más en la parte inferior de la pregunta. Tal como están las cosas, es solo una cantidad aterradora de texto y código que tengo que revisar si quiero saber de qué se trata la pregunta. – jalf
@jalf: Sí, lo siento jalf. No quería crear una respuesta separada porque DeadMG ya respondió correctamente. Supongo que pensé que sería grosero de mi parte hacer eso, aunque pensé que algunas aclaraciones no iban a salir mal para nadie más leyendo esto en el futuro. Y la pregunta extra probablemente debería ser una pregunta completamente separada, ya que no está realmente relacionada con el original. – dvide
En SO, no hay nada de malo en publicar nuevas y mejores respuestas a preguntas que ya han sido respondidas. Y si te sientes mal por eso, solo acepta la respuesta de DeadMG, pero publica la tuya debajo de ella. :) – jalf