tutorial studio programacion móviles libro español desarrollo desarrollar curso aprende aplicaciones c++ templates

studio - Expresiones tipo firma de función como argumentos de plantilla C++



programacion android pdf 2018 (2)

Estaba mirando la FastDelegate Don FastDelegate y noté un extraño truco sintáctico con la siguiente estructura:

TemplateClass< void( int, int ) > Object;

Casi parece que una firma de función se usa como argumento para una declaración de instancia de plantilla.

Esta técnica (cuya presencia en FastDelegate aparentemente se debe a una Jody Hagins) se usó para simplificar la declaración de instancias de plantilla con una cantidad semiarbitraria de parámetros de plantilla.

A saber, permitió esto algo como lo siguiente:

// A template with one parameter template<typename _T1> struct Object1 { _T1 m_member1; }; // A template with two parameters template<typename _T1, typename _T2> struct Object2 { _T1 m_member1; _T2 m_member2; }; // A forward declaration template<typename _Signature> struct Object; // Some derived types using "function signature"-style template parameters template<typename _Dummy, typename _T1> struct Object<_Dummy(_T1)> : public Object1<_T1> {}; template<typename _Dummy, typename _T1, typename _T2> struct Object<_Dummy(_T1, _T2)> : public Object2<_T1, _T2> {}; // A. "Vanilla" object declarations Object1<int> IntObjectA; Object2<int, char> IntCharObjectA; // B. Nifty, but equivalent, object declarations typedef void UnusedType; Object< UnusedType(int) > IntObjectB; Object< UnusedType(int, char) > IntCharObjectB; // C. Even niftier, and still equivalent, object declarations #define DeclareObject( ... ) Object< UnusedType( __VA_ARGS__ ) > DeclareObject( int ) IntObjectC; DeclareObject( int, char ) IntCharObjectC;

A pesar de la verdadera sensación de hackiness, encuentro que este tipo de emulación spoofy de argumentos de plantilla variados es bastante alucinante.

El verdadero truco de este truco parece ser el hecho de que puedo pasar construcciones textuales como "Type1 (Type2, Type3)" como argumentos a las plantillas. Así que aquí están mis preguntas: ¿cómo exactamente el compilador interpreta este constructo? ¿Es una firma de función? O, ¿es solo un patrón de texto con paréntesis? Si el primero, ¿implica esto que cualquier firma de función arbitraria es un tipo válido en lo que respecta al procesador de plantilla?

Una pregunta de seguimiento sería que, dado que el ejemplo de código anterior es un código válido, ¿por qué el estándar de C ++ no le permite hacer algo como lo siguiente, que no se compila?

template<typename _T1> struct Object { _T1 m_member1; }; // Note the class identifier is also "Object" template<typename _T1, typename _T2> struct Object { _T1 m_member1; _T2 m_member2; }; Object<int> IntObject; Object<int, char> IntCharObject;


Con respecto a su primera pregunta sobre el tipo int(char, float) , este es un tipo de C ++ válido y es el tipo de una función que toma un char y un float y devuelve un int . Tenga en cuenta que este es el tipo de la función real, no un puntero a la función, que sería un int (*) (char, float) . El tipo real de cualquier función es este tipo inusual. Por ejemplo, el tipo de

void DoSomething() { /* ... */ }

es void ()

La razón por la que esto no aparece mucho durante la programación de rutina es que en la mayoría de las circunstancias no se pueden declarar variables de este tipo. Por ejemplo, este código es ilegal:

void MyFunction() { void function() = DoSomething; // Error! }

Sin embargo, un caso en el que realmente ve los tipos de funciones utilizados es para pasar punteros a las funciones:

void MyFunction(void FunctionArgument()) { /* ... */ }

Es más común ver este tipo de función escrita para tomar un puntero de función, pero está perfectamente bien incorporar la función en sí misma. Se lanza detrás de las escenas.

En cuanto a su segunda pregunta, por qué es ilegal tener la misma plantilla escrita con diferentes números de argumentos, no sé exactamente la redacción en la especificación que lo prohíbe, pero tiene algo que ver con el hecho de que una vez que haya declaró una plantilla de clase, no puede cambiar la cantidad de argumentos a ella. Sin embargo, puede proporcionar una especialización parcial sobre esa plantilla que tiene un número diferente de argumentos, siempre que, por supuesto, la especialización parcial solo se especialice sobre la cantidad original de argumentos. Por ejemplo:

template <typename T> class Function; template <typename Arg, typename Ret> class Function<Ret (Arg)> { /* ... */ };

Aquí, la Function siempre toma un parámetro. La especialización de plantillas tiene dos argumentos, pero la especialización sigue siendo solo de un tipo (específicamente, Ret (Arg) ).


int* int_pointer; // int_pointer has type "int*" int& int_reference; // int_reference has type "int&" int int_value; // int_value has type "int" void (*function_pointer)(int, int); // function_pointer has type // "void (*)(int, int)" void (&function_reference)(int, int); // function_reference has type // "void (&)(int ,int)" void function(int, int); // function has type // "void(int, int)" template<> struct Object1<void(int, int)> { void m_member1(int, int); // wait, what?? not a value you can initialize. };