简体   繁体   English

C++ 中 typedef 的前向声明

[英]Forward declaration of a typedef in C++

Why won't the compiler let me forward declare a typedef?为什么编译器不让我转发声明 typedef?

Assuming it's impossible, what's the best practice for keeping my inclusion tree small?假设这是不可能的,保持我的包含树小的最佳做法是什么?

You can do forward typedef.你可以做前向typedef。 But to do但是要做

typedef A B;

you must first forward declare A :您必须首先转发声明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...对于像我这样希望在某些 C++ 代码中向前声明使用 typedef 定义的 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;
 }

To "fwd declare a typedef" you need to fwd declare a class or a struct and then you can typedef declared type.要“fwd 声明 typedef”,您需要 fwd 声明一个类或结构,然后您可以 typedef 声明类型。 Multiple identical typedefs are acceptable by compiler.编译器可以接受多个相同的 typedef。

long form:长表:

class MyClass;
typedef MyClass myclass_t;

short form:简写:

typedef class MyClass myclass_t;

In C++ (but not plain C), it's perfectly legal to typedef a type twice, so long as both definitions are completely identical:在 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);

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.您可以转发声明一个指向该类型的指针,或者 typedef 一个指向该类型的指针。

If you really want to, you can use the pimpl idiom to keep the includes down.如果你真的想要,你可以使用 pimpl idiom 来减少包含。 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.编辑: j_random_hacker 为这个答案添加了一个重要的限定条件,基本上需要知道大小才能使用类型,但是如果我们只需要知道类型存在,则可以进行前向声明,以便创建指向类型。 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.由于 OP 没有显示代码,但抱怨它无法编译,我假设(可能正确)OP 正在尝试使用该类型,而不仅仅是引用它。

Using forward declarations instead of a full #include s is possible only when you are not intending on using the type itself (in this file's scope) but a pointer or reference to it.仅当您打算使用类型本身(在此文件的范围内)而是使用指针或引用时,才可以使用前向声明而不是完整的#include

To use the type itself, the compiler must know its size - hence its full declaration must be seen - hence a full #include is needed.要使用类型本身,编译器必须知道它的大小——因此必须看到它的完整声明——因此需要完整的#include

However, the size of a pointer or reference is known to the compiler, regardless of the size of the pointee, so a forward declaration is sufficient - it declares a type identifier name.但是,无论指针对象的大小如何,编译器都知道指针或引用的大小,因此前向声明就足够了——它声明了一个类型标识符名称。

Interestingly, when using pointer or reference to class or struct types, the compiler can handle incomplete types saving you the need to forward declare the pointee types as well:有趣的是,当使用指针或对classstruct类型的引用时,编译器可以处理不完整的类型,从而节省您转发声明指针类型的需要:

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

I had the same issue, didn't want to mess with multiple typedefs in different files, so I resolved it with inheritance:我有同样的问题,不想弄乱不同文件中的多个 typedef,所以我通过继承解决了它:

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 (?).我用继承和构造函数继承(?)替换了typedef (具体来说是using )。

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:这样我就可以转发声明CallStack

class CallStack;

As Bill Kotsias noted, the only reasonable way to keep the typedef details of your point private, and forward declare them is with inheritance.正如 Bill Kotsias 所指出的,保持点的 typedef 详细信息私有并转发声明它们的唯一合理方法是继承。 You can do it a bit nicer with C++11 though.不过,您可以使用 C++11 做得更好。 Consider this:考虑一下:

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

Like @BillKotsias, I used inheritance, and it worked for me.像@BillKotsias 一样,我使用了继承,它对我有用。

I changed this mess (which required all the boost headers in my declaration *.h)我改变了这个烂摊子(这需要我的声明 *.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;

into this declaration (*.h)进入此声明 (*.h)

class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;

and the implementation (*.cpp) was并且实施(* .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
>>
{
};

Another solution is to put the forward declarations and typedefs into a separate header and include that:另一种解决方案是将前向声明和 typedef 放入单独的标头中,并包括:

// 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.您可以在同一个文件中添加更多前向声明并将其包含在相关位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM