在C ++中转发typedef的声明

时间:2009-04-30 00:21:06

标签: c++ typedef forward-declaration

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

假设这是不可能的,保持包含树的最佳做法是什么?

10 个答案:

答案 0 :(得分:156)

你可以转发typedef。但要做到

typedef A B;

您必须先转发声明A

class A;

typedef A B;

答案 1 :(得分:41)

对于那些喜欢我的人,他们正在寻求使用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;
 }

答案 2 :(得分:16)

在C ++中(但不是普通的C),只要两个定义完全完全相同,输入两次类型就完全合法了:

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

答案 3 :(得分:16)

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

长篇:

class MyClass;
typedef MyClass myclass_t;

简短形式:

typedef class MyClass myclass_t;

答案 4 :(得分:11)

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

如果你真的想,你可以使用pimpl成语来保持包含下来。但是如果你想使用一个类型而不是指针,编译器必须知道它的大小。

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

答案 5 :(得分:6)

只有当打算使用类型本身(在此文件的范围内)时才可以使用正式声明而不是的完整#include但是指针或对它的引用。

要使用类型本身,编译器必须知道它的大小 - 因此必须看到它的完整声明 - 因此需要一个完整的#include

但是,无论指针对象的大小如何,编译器都知道指针或引用的大小,因此前向声明就足够了 - 它声明了一个类型标识符名称。

有趣的是,当使用指向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 

答案 6 :(得分:2)

我遇到了同样的问题,并不想在不同的文件中混淆多个typedef,所以我用继承来解决它:

是:

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

答案 7 :(得分:0)

正如Bill Kotsias所指出的那样,唯一合理的方法是保持你的点的typedef细节是私有的,并且转发声明它们是继承。你可以用C ++ 11做得更好。考虑一下:

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

答案 8 :(得分:0)

就像@BillKotsias一样,我使用了继承,它对我有用。

我改变了这个混乱(它需要我声明中的所有提升标题* .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;

进入此声明(* .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
>>
{
};

答案 9 :(得分:0)

我用继承和构造函数继承(?)代替了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;