2012-06-13 27 views
8

¡Yay, otro título de pregunta compuesto por una secuencia aleatoria de términos de C++!Función de conversión con plantilla para el puntero de función

Normalmente hacemos una clase invocable implementando operator(). Pero también puede hacerlo implementando una conversión definida por el usuario a un puntero de función o tipo de referencia. En lugar de utilizar el reenvío perfecto, una función de conversión puede devolver un puntero a una función que luego se llama con la lista de argumentos original.

struct call_printf { 
    typedef int printf_t(char const *, ...); 
    operator printf_t &() { return std::printf; } 
}; 

http://ideone.com/kqrJz

Por lo que yo puedo decir, la typedef anterior es una necesidad sintáctica. El nombre de una función de conversión se forma a partir de type-specifier-seq, que no permite una construcción como int (*)(). Eso requeriría un resumen-declarador. Presumiblemente, la razón es que tales nombres de tipos se vuelven complicados, y los constructos complejos utilizados como nombres de objetos son difíciles de analizar.

Las funciones de conversión también pueden ser modeladas, pero los argumentos de la plantilla deben deducirse, porque no hay ningún lugar para especificarlos explícitamente. (Eso acabaría con el punto central de la conversión implícita.)


Pregunta # 1: En C++ 03, es decir que no había manera de especificar una plantilla encargado de la conversión de la función? Parece que no había forma de resolver los argumentos de la plantilla (es decir, nombrarlos en un contexto deducido) en un tipo de puntero de función aceptable.

Aquí está la referencia equivalente de C++ 11, §13.3.1.1.2/2 [over.call.object]. Es sustancialmente la misma a partir de C++ 03:

Además, para cada función de conversión no explícita declarada en T de la forma

operator conversion-type-id() cv-qualifier attribute-specifier-seqopt; 

donde cv-calificador es el mismo CV- calificación como, o una mayor cv-calificación que, cv, y donde conversión de tipo-id indica la “puntero a función de (P1, ..., Pn) devolver R” tipo, o el tipo "Referencia al puntero a la función de (P1, ..., P n) devolver R”, o el tipo de‘referencia a la función de (P1, ..., Pn) devolver R’, una función de llamada sustituto con la llamada función nombre único y que tiene la forma

R call-function (conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1,... ,an); } 

es también se considera como una función candidata. De forma similar, las funciones de llamada indirecta se agregan al conjunto de funciones candidatas para cada función de conversión no explícita declarada en una clase base de T, siempre que la función no esté oculta dentro de T por otra declaración intermedia.


Pregunta # 2: En C++ 11, puede tal conversión puede especificar mediante un argumento de plantilla por defecto? Esto es útil para SFINAE. La única diferencia aquí del ejemplo anterior es que id-conversión-conversión solo representa una referencia de función después de la instanciación, porque es un tipo dependiente (a pesar de la invarianza).Esto activa GCC y omite la plantilla de miembro.

enum { call_alternate = true; } 

struct call_switch { 
    template< bool en = call_alternate > 
    operator typename std::enable_if< en, decltype(fn_1) & >::type() 
     { return fn_1; } 

    template< bool en = ! call_alternate > 
    operator typename std::enable_if< en, decltype(fn_2) & >::type() 
     { return fn_2; } 
}; 

También tenemos plantillas de alias. Parece que la sustitución de alias ocurre antes de la instanciación, dado el ejemplo en §14.5.7/2, donde las declaraciones de process entran en conflicto. En GCC 4.7, este código al menos ejemplifica la declaración, pero luego produce un extraño "candidato espera 2 argumentos, 2 proporcionado" error.

template< typename t > 
using fn_t = void (&)(t); 

struct talk { 
    template< typename t > 
    operator fn_t<t>() { return fn; } 
}; 

int main() { 
    talk()(3); 
} 
+7

Mi bondad .... –

+0

¿Qué estás tratando de hacer? ¿Dónde puede ser útil? – Nawaz

+0

@Nawaz cuando quiere que un operador de conversión funcione con tipos de puntero? –

Respuesta

3

Pregunta # 1: En C++ 03, es que no había manera de especificar una plantilla encargado de la conversión de la función? Parece que no había forma de resolver los argumentos de la plantilla (es decir, nombrarlos en un contexto deducido) en un tipo de puntero de función aceptable.

Sí, eso es correcto.

Pregunta n. ° 2: En C++ 11, ¿puede especificarse tal conversión utilizando un argumento de plantilla predeterminado?

Puede, y también puede usar plantillas de alias, pero no puede usar dicha plantilla de función de conversión para crear funciones de llamada indirectas. Puede usarlo para convertir su objeto de clase a punteros de función en conversiones implícitas.

También tenemos plantillas de alias. Parece que la sustitución de alias ocurre antes de la instanciación, dado el ejemplo en §14.5.7/2, donde las declaraciones de proceso entran en conflicto. En GCC 4.7, este código al menos ejemplifica la declaración, pero luego produce un extraño "candidato espera 2 argumentos, 2 proporcionado" error.

Sí, esto es https://groups.google.com/forum/?fromgroups#!topic/comp.std.c++/lXLFBcF_m3c (y ha causado el cierre de DR395), pero a pesar de que tales una plantilla de función de conversión puede trabajar en casos como void(&p)() = yourClassObject, no va a funcionar las funciones de llamada sustitutivos, porque allí las necesidades función de conversión para proporcionar un tipo fijo no dependiente al que se convierte el objeto de clase cuando se llama a la función sustituta, pero una plantilla de función de conversión no proporciona ese tipo normalmente (cosas extrañas como template<typename = int> operator Identity<void(*)()>(); aparte ...).

creo que GCC puede genera incorrectamente el candidato call-function(void (&)(t), t) con los tipos dependientes todavía allí y tratar de llamar a ese candidato, violando con ello algunos invariantes de ella (lo que podría explicar el mensaje de error raro - posiblemente lanzó un } else { ... } inesperadamente en algún lugar).

+0

Gran respuesta, excepto "debe quedar claro" ¿por qué? La frase "función de conversión declarada en T de la forma' operator' * conversion-type-id * '()' "no dice nada acerca de no ser una plantilla. – Potatoswatter

+0

@Potatoswatter, creo que es una omisión en la especificación. Pero simplemente no tiene sentido para mí considerar las plantillas de función de conversión aquí. ¿Cuál debería ser la semántica? –

+0

Siempre que el tipo de función se pueda deducir de la lista de argumentos utilizando la resolución de sobrecarga, no se necesita ninguna semántica especial.Eso es lo que hace GCC (a mitad de camino). Esencialmente, la función de llamada sustituta se convierte en una plantilla de función de llamada sustituta. – Potatoswatter

Cuestiones relacionadas