Risposte:
Puoi fare il typedef in avanti. Ma da fare
typedef A B;
devi prima dichiarare A
:
class A;
typedef A B;
typedef
nomi di un tipo di modello multilivello complesso che utilizza una dichiarazione diretta in questo modo è piuttosto complesso e difficile. Per non parlare del fatto che potrebbe essere necessario immergersi nei dettagli dell'implementazione nascosti negli argomenti del modello predefinito. E la soluzione finale è un codice lungo e illeggibile (specialmente quando i tipi provengono da vari spazi dei nomi) molto incline a cambiare nel tipo originale.
Per quelli come voi, che non vedono l'ora di dichiarare una struttura in stile C che è stata definita usando typedef, in un codice c ++ ho trovato una soluzione che procede come segue ...
// 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;
}
Per "dichiarare un typedef" devi dichiarare una classe o una struttura e quindi puoi digitare il tipo dichiarato. Numerosi typedef identici sono accettabili dal compilatore.
forma lunga:
class MyClass;
typedef MyClass myclass_t;
forma breve:
typedef class MyClass myclass_t;
In C ++ (ma non in semplice C), è perfettamente legale digitare un tipo due volte, a condizione che entrambe le definizioni siano completamente identiche:
// 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);
A
campi in questo modo poiché A
è vuoto per definizione?
Perché per dichiarare un tipo, è necessario conoscerne le dimensioni. È possibile inoltrare un puntatore al tipo o digitare un puntatore al tipo.
Se vuoi davvero, puoi usare l'idioma del pimpl per tenere giù le inclusioni. Ma se vuoi usare un tipo, piuttosto che un puntatore, il compilatore deve conoscere le sue dimensioni.
Modifica: j_random_hacker aggiunge una qualifica importante a questa risposta, fondamentalmente che la dimensione deve essere conosciuta per usare il tipo, ma una dichiarazione diretta può essere fatta se dobbiamo solo sapere che il tipo esiste , al fine di creare puntatori o riferimenti al genere. Poiché l'OP non mostrava il codice, ma si lamentava che non si sarebbe compilato, ho ipotizzato (probabilmente correttamente) che l'OP stesse cercando di usare il tipo, non solo di fare riferimento ad esso.
Utilizzando le dichiarazioni previsionali , invece di un pieno di #include
s è possibile solo quando si è non intende utilizzare il tipo stesso (nell'ambito di questo file) ma un puntatore o un riferimento ad esso.
Per usare il tipo stesso, il compilatore deve conoscere le sue dimensioni - quindi deve essere vista la sua dichiarazione completa - quindi #include
è necessario un completo .
Tuttavia, la dimensione di un puntatore o di un riferimento è nota al compilatore, indipendentemente dalla dimensione della punta, quindi una dichiarazione diretta è sufficiente: dichiara un nome identificativo del tipo.
È interessante notare che quando si utilizza il puntatore o il riferimento a class
o struct
tipi, il compilatore può gestire tipi incompleti risparmiando la necessità di inoltrare anche i tipi di punte:
// 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
Ho avuto lo stesso problema, non volevo scherzare con più typedef in file diversi, quindi l'ho risolto con l'ereditarietà:
era:
class BurstBoss {
public:
typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...
ha fatto:
class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{
public:
ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
};
};
Ha funzionato come un fascino. Naturalmente, ho dovuto cambiare qualsiasi riferimento da
BurstBoss::ParticleSystem
semplicemente
ParticleSystem
Ho sostituito il typedef
( using
per essere precisi) con l'ereditarietà e l'ereditarietà del costruttore (?).
Originale
using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;
sostituito
struct CallStack // Not a typedef to allow forward declaration.
: public std::array<StackFrame, MAX_CALLSTACK_DEPTH>
{
typedef std::array<StackFrame, MAX_CALLSTACK_DEPTH> Base;
using Base::Base;
};
In questo modo sono stato in grado di inoltrare la dichiarazione CallStack
con:
class CallStack;
Come notato da Bill Kotsias, l'unico modo ragionevole per mantenere privati i dettagli del tuo punto e inoltrarli è ereditario. Puoi farlo un po 'meglio con C ++ 11. Considera questo:
// 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;
};
Come @BillKotsias, ho usato l'ereditarietà e ha funzionato per me.
Ho cambiato questo pasticcio (che ha richiesto tutte le intestazioni boost nella mia dichiarazione * .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;
in questa dichiarazione (* .h)
class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;
e l'implementazione (* .cpp) era
#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
>>
{
};