Respostas:
Você pode avançar typedef. Mas fazer
typedef A B;
você deve primeiro encaminhar declarar A
:
class A;
typedef A B;
typedef
nomes de um modelo de modelo multinível complexo usando uma declaração de encaminhamento dessa maneira são bastante complexos e difíceis. Sem mencionar que pode ser necessário mergulhar nos detalhes da implementação ocultos nos argumentos do modelo padrão. E a solução final é um código longo e ilegível (especialmente quando os tipos vêm de vários espaços para nome) muito propensos a alterações no tipo original.
Para aqueles que gostam de mim, que desejam encaminhar declarar uma estrutura no estilo C que foi definida usando typedef, em algum código c ++, encontrei uma solução que é a seguinte ...
// 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;
}
Para "declarar um typedef", você precisa declarar uma classe ou uma estrutura e, em seguida, pode digitar o tipo declarado. Vários typedefs idênticos são aceitáveis pelo compilador.
forma longa:
class MyClass;
typedef MyClass myclass_t;
forma curta:
typedef class MyClass myclass_t;
No C ++ (mas não no C), é perfeitamente legal digitar um tipo duas vezes, desde que ambas as definições sejam 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);
A
campos dessa maneira, uma vez que A
é vazio por definição?
Como para declarar um tipo, seu tamanho precisa ser conhecido. Você pode encaminhar declarar um ponteiro para o tipo ou digitar um ponteiro para o tipo.
Se você realmente deseja, pode usar o idioma pimpl para manter as inclusões baixas. Mas se você deseja usar um tipo, e não um ponteiro, o compilador precisa saber seu tamanho.
Edit: j_random_hacker adiciona uma qualificação importante a esta resposta, basicamente que o tamanho precisa ser conhecido para usar o tipo, mas uma declaração direta pode ser feita se precisarmos apenas saber que o tipo existe , a fim de criar ponteiros ou referências para o tipo tipo. Como o OP não mostrou código, mas reclamou que não seria compilado, presumi (provavelmente corretamente) que o OP estava tentando usar o tipo, não apenas se referindo a ele.
O uso de declarações avançadas em vez de um #include
s completo é possível apenas quando você não pretende usar o próprio tipo (no escopo deste arquivo), mas um ponteiro ou referência a ele.
Para usar o próprio tipo, o compilador deve conhecer seu tamanho - portanto, sua declaração completa deve ser vista -, portanto, #include
é necessário um total .
No entanto, o tamanho de um ponteiro ou referência é conhecido pelo compilador, independentemente do tamanho do apontador, portanto, uma declaração de encaminhamento é suficiente - ele declara um nome de identificador de tipo.
Curiosamente, ao usar ponteiro ou referência a class
ou struct
tipos, o compilador pode lidar com tipos incompletos, economizando a necessidade de encaminhar também os tipos de ponta de ponte:
// 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
Eu tinha o mesmo problema, não queria mexer com vários typedefs em arquivos diferentes, então resolvi com herança:
foi:
class BurstBoss {
public:
typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...
fez:
class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{
public:
ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
};
};
Funcionou como um encanto. Claro, eu tive que mudar as referências de
BurstBoss::ParticleSystem
simplesmente
ParticleSystem
Substituí o typedef
( using
para ser específico) por herança e herança de construtor (?).
Original
using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;
Substituído
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;
};
Dessa forma, eu pude encaminhar declarar CallStack
com:
class CallStack;
Como Bill Kotsias observou, a única maneira razoável de manter os detalhes digitados do seu ponto em particular, e depois declará-los é com herança. Você pode fazê-lo um pouco melhor com o C ++ 11. Considere isto:
// 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;
};
Como @BillKotsias, eu usei herança, e funcionou para mim.
Eu mudei essa bagunça (que exigia todos os cabeçalhos de impulso na minha declaração * .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;
nesta declaração (* .h)
class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;
e a implementação (* .cpp) foi
#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
>>
{
};