Why won't the compiler let me forward declare a typedef?
Assuming it's impossible, what's the best practice for keeping my inclusion tree small?
Why won't the compiler let me forward declare a typedef?
Assuming it's impossible, what's the best practice for keeping my inclusion tree small?
You can do forward typedef. But to do
typedef A B;
you must first forward declare A:
class A;
typedef A B;
For those of you like me, who are looking to forward declare a C-style struct that was defined using typedef, in some c++ code, I have found a solution that goes as follows...
// 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;
}
In C++ (but not plain C), it's perfectly legal to typedef a type twice, so long as both definitions are completely identical:
// 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);
Because to declare a type, its size needs to be known. You can forward declare a pointer to the type, or typedef a pointer to the type.
If you really want to, you can use the pimpl idiom to keep the includes down. But if you want to use a type, rather than a pointer, the compiler has to know its size.
Edit: j_random_hacker adds an important qualification to this answer, basically that the size needs to be know to use the type, but a forward declaration can be made if we only need to know the type exists, in order to create pointers or references to the type. Since the OP didn't show code, but complained it wouldn't compile, I assumed (probably correctly) that the OP was trying to use the type, not just refer to it.
I had the same issue, didn't want to mess with multiple typedefs in different files, so I resolved it with inheritance:
was:
class BurstBoss {
public:
typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...
did:
class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{
public:
ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
};
};
Worked like a charm. Of course, I had to change any references from
BurstBoss::ParticleSystem
to simply
ParticleSystem
I replaced the typedef (using to be specific) with inheritance and constructor inheritance (?).
Original
using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;
Replaced
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;
};
This way I was able to forward declare CallStack with:
class CallStack;
Like @BillKotsias, I used inheritance, and it worked for me.
I changed this mess (which required all the boost headers in my declaration *.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;
into this declaration (*.h)
class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;
and the implementation (*.cpp) was
#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
>>
{
};
Another solution is to put the forward declarations and typedefs into a separate header and include that:
// ForwardDeclarations.h
#pragma once
namespace Foo
{
struct Bar;
typedef Bar Baz;
}
// SomeFile.h
#include "ForwardDeclarations.h"
Foo::Baz baz;
Of course this doesn't actually reduce the number of files to include and the compiler still has to read this file from the disk, but at least the contents are simpler than the full definition. You could add more forward declarations to the same file and include it in relevant places.