c++ typedef forward-declaration

Declaración de reenvío de un typedef en C++



forward-declaration (9)

¿Por qué el compilador no me permite reenviar un typedef?

Suponiendo que es imposible, ¿cuál es la mejor práctica para mantener pequeño mi árbol de inclusión?


Como @BillKotsias, usé la herencia, y funcionó para mí.

Cambié este desorden (que requería todos los encabezados de refuerzo en mi declaración * .h)

#include <boost/accumulators/accumulators.hpp> #include <boost/accumulators/statistics.hpp> #include <boost/accumulators/statistics/stats.hpp> #include <boost/accumulators/statistics/mean.hpp> #include <boost/accumulators/statistics/moment.hpp> #include <boost/accumulators/statistics/min.hpp> #include <boost/accumulators/statistics/max.hpp> typedef boost::accumulators::accumulator_set<float, boost::accumulators::features< boost::accumulators::tag::median, boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max >> VanillaAccumulator_t ; std::unique_ptr<VanillaAccumulator_t> acc;

en esta declaración (* .h)

class VanillaAccumulator; std::unique_ptr<VanillaAccumulator> acc;

y la implementación (* .cpp) fue

#include <boost/accumulators/accumulators.hpp> #include <boost/accumulators/statistics.hpp> #include <boost/accumulators/statistics/stats.hpp> #include <boost/accumulators/statistics/mean.hpp> #include <boost/accumulators/statistics/moment.hpp> #include <boost/accumulators/statistics/min.hpp> #include <boost/accumulators/statistics/max.hpp> class VanillaAccumulator : public boost::accumulators::accumulator_set<float, boost::accumulators::features< boost::accumulators::tag::median, boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max >> { };


Como señaló Bill Kotsias, la única manera razonable de mantener en privado los detalles de typedef de su punto y los puede declarar con herencia. Aunque puedes hacerlo un poco mejor con C ++ 11. Considera esto:

// LibraryPublicHeader.h class Implementation; class Library { ... private: Implementation* impl; };

// LibraryPrivateImplementation.cpp // This annoyingly does not work: // // typedef std::shared_ptr<Foo> Implementation; // However this does, and is almost as good. class Implementation : public std::shared_ptr<Foo> { public: // C++11 allows us to easily copy all the constructors. using shared_ptr::shared_ptr; };


Debido a que para declarar un tipo, su tamaño debe ser conocido. Puede reenviar declarar un puntero al tipo, o escribir un puntero al tipo.

Si realmente lo deseas, puedes usar el lenguaje pimpl para mantener los contenidos bajos. Pero si desea utilizar un tipo, en lugar de un puntero, el compilador debe saber su tamaño.

Edit: j_random_hacker agrega una calificación importante a esta respuesta, básicamente, que el tamaño debe ser conocido para usar el tipo, pero se puede hacer una declaración hacia adelante si solo necesitamos saber que existe el tipo, para crear punteros o referencias al tipo. Como el OP no mostraba el código, pero se quejaba de que no se compilaba, asumí (probablemente correctamente) que el OP intentaba usar el tipo, no solo se refería a él.


El uso de declaraciones de reenvío en lugar de un #include s completo es posible solo cuando no tiene la intención de usar el tipo en sí (en el alcance de este archivo), sino un puntero o una referencia a él.

Para usar el tipo en sí, el compilador debe conocer su tamaño; por lo tanto, se debe ver su declaración completa; por lo tanto, se necesita un #include completo.

Sin embargo, el compilador conoce el tamaño de un puntero o referencia, independientemente del tamaño del pointee, por lo que una declaración de reenvío es suficiente: declara un nombre de identificador de tipo.

Curiosamente, cuando se usa un puntero o una referencia a class tipos de class o struct , el compilador puede manejar tipos incompletos, lo que le ahorra la necesidad de reenviar y declarar los tipos de pointee también:

// header.h // Look Ma! No forward declarations! typedef class A* APtr; // class A is an incomplete type - no fwd. decl. anywhere typedef class A& ARef; typedef struct B* BPtr; // struct B is an incomplete type - no fwd. decl. anywhere typedef struct B& BRef; // Using the name without the class/struct specifier requires fwd. decl. the type itself. class C; // fwd. decl. type typedef C* CPtr; // no class/struct specifier typedef C& CRef; // no class/struct specifier struct D; // fwd. decl. type typedef D* DPtr; // no class/struct specifier typedef D& DRef; // no class/struct specifier


En C ++ (pero no en C simple), es perfectamente legal tipear un tipo dos veces, siempre que ambas definiciones sean completamente idénticas:

// foo.h struct A{}; typedef A *PA; // bar.h struct A; // forward declare A typedef A *PA; void func(PA x); // baz.cc #include "bar.h" #include "foo.h" // We''ve now included the definition for PA twice, but it''s ok since they''re the same ... A x; func(&x);


Para "fwd declare un typedef" necesita fwd declarar una clase o una estructura y luego puede escribir typedef tipo declarado. Múltiples typedefs idénticos son aceptables por compilador.

forma larga:

class MyClass; typedef MyClass myclass_t;

forma corta:

typedef class MyClass myclass_t;


Para aquellos de ustedes como yo, que están buscando declarar en adelante una estructura de estilo C que se definió usando typedef, en algunos códigos de C ++, he encontrado una solución que sigue como sigue ...

// a.h typedef struct _bah { int a; int b; } bah; // b.h struct _bah; typedef _bah bah; class foo { foo(bah * b); foo(bah b); bah * mBah; }; // b.cpp #include "b.h" #include "a.h" foo::foo(bah * b) { mBah = b; } foo::foo(bah b) { mBah = &b; }


Tuve el mismo problema, no quería meterme con varias definiciones de tipo en diferentes archivos, así que lo resolví con herencia:

estaba:

class BurstBoss { public: typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...

hizo:

class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool> { public: ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) { }; };

Trabajado como un encanto. Por supuesto, tuve que cambiar cualquier referencia de

BurstBoss::ParticleSystem

simplemente

ParticleSystem


Usted puede hacer typedef adelante. Pero hacer

typedef A B;

Primero debe reenviar declarar A :

class A; typedef A B;