在C++中转发typedef的声明

use*_*825 221 c++ typedef forward-declaration

编译器为什么不让我转发声明一个typedef?

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

Hon*_*ang 161

你可以转发typedef.但要这样做

typedef A B;
Run Code Online (Sandbox Code Playgroud)

你必须先转发声明A:

class A;

typedef A B;
Run Code Online (Sandbox Code Playgroud)

  • 通常,这不是一个有用的解决方案.例如,如果`typedef`使用前向声明命名复杂的多级模板类型,则这种方式相当复杂和困难.更不用说它可能需要深入隐藏在默认模板参数中的实现细节.最终解决方案是一个冗长且不可读的代码(特别是当类型来自各种命名空间时)非常容易改变原始类型. (46认同)
  • 这对于模板化的课程来说并不适用. (15认同)
  • 最后+1,因为虽然你在技术上不能"forward-typedef"(即你不能写"typedef A;"),你几乎可以肯定地完成了OP想要使用上面的技巧完成的事情. (10认同)
  • 但请注意,如果typedef更改,您也可以更改所有这些前向声明,如果旧的和新的typedef使用具有相同接口的类型,则可能会错过. (9认同)
  • @windfinder:它确实:template <class T> class A; typedef A <C> B; (3认同)
  • 这也显示了"实现细节"(即使不完全但仍然......),而前向声明背后的想法是隐藏它们. (2认同)

小智 45

对于那些喜欢我的人,谁想要使用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;
 }
Run Code Online (Sandbox Code Playgroud)

  • @LittleJohn此解决方案的问题在于,假名_bah不被视为公共API的一部分。请参见正向delcare文件。 (2认同)

Pav*_*l P 20

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

长表:

class MyClass;
typedef MyClass myclass_t;
Run Code Online (Sandbox Code Playgroud)

简写:

typedef class MyClass myclass_t;
Run Code Online (Sandbox Code Playgroud)

  • @JorgeLeitão 你看不出有什么不同?它没有在一行中显示如何做到这一点。 (2认同)

Ada*_*eld 17

在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);
Run Code Online (Sandbox Code Playgroud)

  • 维护否否.这种事情迟早会把你咬在keister中. (34认同)
  • @MarkStorer,至少编译器会捕获任何差异并生成错误.我用Visual C++验证了这一点. (3认同)

tpd*_*pdi 10

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

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

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

  • 好吧,类类型的前向声明声明这些类型而不知道它们的大小.此外,除了能够定义指针和对这些不完整类型的引用之外,还可以声明(但未定义)函数,这些函数接受参数和/或返回这些类型的值. (35认同)
  • 对不起,我不认为这是一个很好的假设.这个答案与此无关.这就是typedef前向声明的情况. (3认同)

Adi*_*vit 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 
Run Code Online (Sandbox Code Playgroud)