C++ 中 typedef 的前向声明

问题描述 投票:0回答:11

为什么编译器不允许我转发声明 typedef?

假设这是不可能的,那么保持我的包含树较小的最佳实践是什么?

c++ typedef forward-declaration
11个回答
199
投票

你可以做forward typedef。但要做

typedef A B;

必须先转发声明

A
:

class A;

typedef A B;

54
投票

对于像我这样希望向前声明使用 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;
 }

39
投票

要“fwd 声明 typedef”,您需要 fwd 声明一个类或一个结构,然后您可以使用 typedef 声明类型。编译器可以接受多个相同的 typedef。

typedef class MyClass myclass_t;

16
投票

在 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);

9
投票

因为声明一个类型,需要知道它的大小。您可以转发声明指向该类型的指针,或 typedef 指向该类型的指针。

如果您确实愿意,可以使用 pimpl 习惯用法来保留包含内容。但如果您想使用类型而不是指针,编译器必须知道它的大小。

编辑:j_random_hacker 对此答案添加了一个重要的限定条件,基本上需要知道大小才能使用类型,但是如果我们只需要知道类型exists,就可以进行前向声明,以便创建类型的指针或引用。由于OP没有显示代码,但抱怨它无法编译,我假设(可能是正确的)OP正在尝试使用类型,而不仅仅是引用它。


8
投票
仅当您

打算使用类型本身(在此文件的范围内)而是使用对其的指针或引用时,才可以使用前向声明而不是完整的

#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



4
投票
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;



2
投票

是:

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



2
投票

// 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;
};


0
投票

我改变了这个混乱(这需要我的声明 *.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 >> { };



0
投票

// ForwardDeclarations.h #pragma once namespace Foo { struct Bar; typedef Bar Baz; } // SomeFile.h #include "ForwardDeclarations.h" Foo::Baz baz;

当然,这实际上并没有减少要包含的文件数量,编译器仍然需要从磁盘读取该文件,但至少内容比完整定义更简单。您可以向同一文件添加更多前向声明并将其包含在相关位置。

© www.soinside.com 2019 - 2024. All rights reserved.