2012-01-15 16 views
13

C++ 03 le permite calificar los parámetros de la función como const, volatile y/o referencias lvalue (&).C++ 11: ¿Resumiendo sobre const, volátil, referencia de lval y punteros de función calificada de referencia de referencia de rvalue?

C++ 11 agrega uno más: referencias rvalue (&&).

Además, C++ le permite sobrecargar funciones basadas en los calificadores de sus parámetros, de modo que se seleccione la sobrecarga más apropiada al llamar a la función.

Una función de miembro se puede concebir conceptualmente como una función que toma un parámetro extra, cuyo tipo es una referencia a una instancia de la clase de la que es miembro. Es posible sobrecargar una función de miembro basada en los calificadores de este 'parámetro adicional' de la misma manera que cualquier otro parámetro. Esto se expresa poniendo la fase de clasificación al final de la función de firma:

struct Foo 
{ 
    int& data();    // return a non-const reference if `this` is non-const 
    const int& data() const; // return a const reference if `this` is const 
}; 

en C++ 03, const y volatile calificadores son posibles, y C++ 11 también permite & y && (& en teoría podría tener permitido en C++ 03, pero no fue así).

Cualquier combinación de calificadores se puede utilizar, con la excepción de que & y && son mutuamente excluyentes, lo que hace por 2^2 = 4 posibilidades en C++ 03 y 2^4-4 = 12 en C++ 11 .

Esto puede ser bastante molesto cuando se quiere trabajar con punteros de función miembro, porque ni siquiera son un poco polimórficos en estos calificadores: los calificadores en el tipo "this" de un puntero de función miembro pasaron como El argumento debe coincidir exactamente con el tipo de parámetro que se está transmitiendo. C++ tampoco ofrece una función explícita para abstraer sobre calificadores. En C + + 03, esto estaba más que nada bien, porque tendrías que escribir una versión const y una versión no const ya nadie le importa volatile, pero en el caso patológico en C++ 11 (que no es tan infrecuente como es patológico) podría tener que escribir manualmente hasta 12 sobrecargas. Por función.

yo estaba muy feliz de descubrir que si estás de paso del tipo de la clase envolvente como un parámetro de plantilla y derivan del tipo de un puntero de función miembro de ella, que const y volatile calificadores se permite y se propagan como era de esperar :

template<typename Object> 
struct Bar 
{ 
    typedef int (Object::*Sig)(int); 
}; 

Bar<Baz>;    // Sig will be `int (Baz::*)(int)` 
Bar<const Baz>;   // Sig will be `int (Baz::*)(int) const` 
Bar<volatile Baz>;  // Sig will be `int (Baz::*)(int) volatile` 
Bar<const volatile Baz>; // Sig will be `int (Baz::*)(int) const volatile` 

Esto es mucho mejor que tener que escribir todos los casos manualmente.

Desafortunadamente, no parece funcionar para & y &&.

GCC 4.7 dice:

error: forming pointer to reference type ‘Baz&&’

Pero eso no es demasiado sorprendente, dado que el CCG como de 4.7 aún no cuenta con el apoyo de los calificadores de referencia en this.

También he probado con Clang 3.0, que tiene ese apoyo:

error: member pointer refers into non-class type 'Baz &&'

Oh, bueno.

¿Estoy en lo correcto al concluir que esto no es posible, y que no hay forma de abstraer los calificadores de referencia en el "this type" de los punteros de función de miembro? También se agradecerá cualquier otra técnica para abstraer sobre calificadores (especialmente en this) que no sea en el caso específico cuando se pasa el "tipo this" como un parámetro de plantilla.

(Vale la pena señalar que si C++ no distinguía entre las funciones miembro y las funciones normales, todo sería trivial: usaría el parámetro plantilla como el tipo de un parámetro de la función (puntero), y el argumento de la plantilla se pasará tal como está, calificadores intactos, sin necesidad de pensamiento adicional.)

+1

¿Con qué frecuencia necesita un comportamiento diferente para todas las posibles combinaciones de calificadores? (O, para el caso, incluso dos o tres combinaciones posibles?) –

+1

Si estoy tratando de escribir una abstracción para objetos de tipo función (en el espíritu de std :: function pero no el mismo) entonces la integridad es un objetivo de diseño . Realmente no puedo extrapolar o estimar (con respecto a la frecuencia) pero sé que me he encontrado con esto antes. – glaebhoerl

Respuesta

4

¿Ha pensado simplemente en especializar su plantilla?

Usted puede añadir las dos versiones:

template <typename Object> 
struct Bar<Object&> { 
    typedef int (Object::*Sig)(int)&; 
}; 

template <typename Object> 
struct Bar<Object&&> { 
    typedef int (Object::*Sig)(int)&&; 
}; 

Y entonces el compilador recogerá la especialización derecha (o de reserva para el caso general) de manera apropiada.

Esto lo salva de la cosa const/volatile, pero implica que debe escribir el código 3 veces.

+0

Sí, el hecho de que 'const' y' volátil' se manejen de manera inteligente significa que solo tengo que escribir tres versiones en lugar de doce, lo cual es bueno. – glaebhoerl

Cuestiones relacionadas