为什么编译器不允许我转发声明 typedef?
假设这是不可能的,那么保持我的包含树较小的最佳实践是什么?
你可以做forward typedef。但要做
typedef A B;
必须先转发声明
A
:
class A;
typedef A B;
对于像我这样希望向前声明使用 typedef 定义的 C 风格结构的人,在某些 C++ 代码中,我找到了如下解决方案...
// 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;
}
要“fwd 声明 typedef”,您需要 fwd 声明一个类或一个结构,然后您可以使用 typedef 声明类型。编译器可以接受多个相同的 typedef。
typedef class MyClass myclass_t;
在 C++ 中(但不是普通的 C),两次 typedef 一个类型是完全合法的,只要两个定义完全相同:
// 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);
因为声明一个类型,需要知道它的大小。您可以转发声明指向该类型的指针,或 typedef 指向该类型的指针。
如果您确实愿意,可以使用 pimpl 习惯用法来保留包含内容。但如果您想使用类型而不是指针,编译器必须知道它的大小。
编辑:j_random_hacker 对此答案添加了一个重要的限定条件,基本上需要知道大小才能使用类型,但是如果我们只需要知道类型exists,就可以进行前向声明,以便创建类型的指针或引用。由于OP没有显示代码,但抱怨它无法编译,我假设(可能是正确的)OP正在尝试使用类型,而不仅仅是引用它。
不打算使用类型本身(在此文件的范围内)而是使用对其的指针或引用时,才可以使用前向声明而不是完整的
#include
。
要使用类型本身,编译器必须知道其大小 - 因此必须查看其完整声明 - 因此需要完整的 #include
。
但是,无论指针对象的大小如何,编译器都知道指针或引用的大小,因此前向声明就足够了 - 它声明了类型标识符名称。
有趣的是,当使用指针或对
class
或
struct
类型的引用时,编译器可以处理 不完整类型,从而使您无需转发声明指针对象类型:
// 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
typedef
(具体来说是
using
)。原创
using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;
已更换
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;
};
这样我就可以通过以下方式转发声明
CallStack
:
class CallStack;
是:
class BurstBoss {
public:
typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...
做了:
class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{
public:
ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
};
};
效果非常好。当然,我必须更改的所有参考文献
BurstBoss::ParticleSystem
简单地
ParticleSystem
// 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;
};
我改变了这个混乱(这需要我的声明 *.h 中的所有 boost 标头)
#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;
进入此声明(*.h)
class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;
实现(*.cpp)是
#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
>>
{
};
// ForwardDeclarations.h
#pragma once
namespace Foo
{
struct Bar;
typedef Bar Baz;
}
// SomeFile.h
#include "ForwardDeclarations.h"
Foo::Baz baz;
当然,这实际上并没有减少要包含的文件数量,编译器仍然需要从磁盘读取该文件,但至少内容比完整定义更简单。您可以向同一文件添加更多前向声明并将其包含在相关位置。