c++ - tipos - typedef struct uso
¿Hay casos en que un typedef es absolutamente necesario? (8)
Considere el siguiente extracto de la expresión bool segura :
typedef void (Testable::*bool_type)() const;
operator bool_type() const;
¿Es posible declarar la función de conversión sin typedef? Lo siguiente no compila:
operator (void (Testable::*)() const)() const;
Ah, acabo de recordar la metafunción de identity
. Es posible escribir
operator typename identity<void (Testable::*)() const>::type() const;
con la siguiente definición de identity
:
template <typename T>
struct identity
{
typedef T type;
};
Se podría argumentar que la identity
todavía usa un typedef
, pero esta solución es "lo suficientemente buena" para mí.
En C ++ 11, puedes hacerlo así (gcc 4.5.2):
operator decltype((void (Testable::*)() const)(0))() const ;
No digo que sea bonito ...
Me encontré con este problema, con clang ++:
foo.cpp:17:8: error: must use a typedef to declare a conversion to ''void (*(int))()''
y hay una plantilla C ++ 11 STL que cubre la funcionalidad identidad <T>:
#include <type_traits>
…
struct foo {
void bar( ) const { }
operator std::common_type<void(foo::*)( )const>::type( ) { return &foo::bar; }
};
Mi análisis dice que no es posible sin usar typedef
. El compilador ve (
como el primer token y supone que está sobrecargando al () operator
, que no debería tener ningún argumento (los argumentos vendrían en el siguiente conjunto de paréntesis). Poner cualquier conjunto de paréntesis adicionales tampoco ayudaría, pero lo haría realmente confunde el compilador y, por lo tanto, establece más errores.
La mayor parte del código STL está en la parte superior de las inscripciones typedef
, ¡y debemos / debemos usarlas!
Parece que la gramática exige usar un typedef en tu caso. Un ID de función de conversión debe ser del operador de forma -conversión-id . La conversión-tipo-id no puede contener paréntesis. Por lo tanto, debe usar typedef al convertir a un tipo de puntero a función, o a un tipo de función de puntero a miembro.
Respondiendo "¿Hay casos en que un typedef es absolutamente necesario?" del título de la pregunta, aquí hay un ejemplo de dónde se necesita un typedef:
f(unsigned char()); // compiler error!
typedef unsigned char Byte;
f(Byte()); // fine!
Vea los resultados aquí: http://ideone.com/JPUra
Un typedef
no es una macro, su segundo ejemplo no es equivalente al primero. En el primer caso su typedef
está definiendo un functor y luego usando ese tipo en un operador de conversión del tipo de functor. En el segundo, el operador está utilizando una sintaxis mala ya que no se ha especificado ningún operador porque no hay ningún tipo. No estoy seguro de cómo escribirlo, pero por lo general hay una manera.
Los typedefs no son realmente necesarios, excepto para hacer código legible para humanos en TMP e incluso entonces depende del tipo de humano que seas.
Como no puedo encontrar la sintaxis alternativa, tal vez los typedefs sean necesarios en algunos casos. Solo pensé en otro posiblemente. Supongamos que tiene una plantilla con especializaciones que contenía un método estático con un tipo de devolución como el siguiente:
template <typename T>
struct WhateverHandler
{
typedef T rType;
static rType Whatever() { return rType(); }
};
template <>
struct WhateverHandler<std::string>
{
typedef std::string rType;
static rType Whatever() { return rType(); }
};
Creo que en este caso también necesitaría el typedef para llamar al método estático independientemente de la especialización, ya que de lo contrario el método podría confundir al compilador porque los tipos de retorno serían diferentes pero no sería una sobrecarga adecuada.
template <typename T>
struct WhateverUser
{
typename WhateverHandler<T>::rType DoWhatever()
{
return WhateverHandler<T>::template Whatever();
}
};
Un caso (no relacionado con su pregunta) donde se requiere un typedef
es cuando se usa el
va_arg()
macro. Citando el estándar C99 (7.15.1.1):
tipo * va_arg (va_list ap, tipo );
...
El tipo de parámetro debe ser un nombre de tipo especificado de modo que el tipo de un puntero a un objeto que tiene el tipo especificado se pueda obtener simplemente postfijando un * al tipo