未命名结构的前向声明

赏金问题:所以,这两个Foo不是一回事。 精细。 第二种forms是在图书馆给出的。 鉴于我无法改变它,我该如何向前申报呢?


我一直认为C和C ++允许重复声明,只要没有重复的定义。 然后,当我试图编写扩展C库的C ++代码时遇到了这个问题。

 struct Foo; typedef struct {} Foo; 

这给出了以下错误:

'结构Foo'有一个前面的声明'结构Foo'

我想向前宣布,补充! 这里有什么问题?

typedef-an匿名结构是在C ++ 03之前进行的一种实践,主要是为了保持与C99之前的编译器的兼容性。

鉴于这是2011年,并且C ++和C都改变了,我想知道为什么没有更多的这样的库的最新版本!

如果它不在发展中,你不能“离开”,而只是“生存”,改变它是这样做的方式。 如果仍在部署中,请将问题提交给开发组。

如果您需要解决方法,请考虑该结构可以inheritance。 所以,写一个前向声明就好

 struct MyFoo; 

并将其定义为

 #include "old_library.h" struct MyFoo: public Foo {}; 

而在你所有的代码中,忘记Foo并总是使用MyFoo

你声明两个具有相同名称的不同实体。 第一个struct Foo是一个名为Foo的结构。 第二个是匿名结构的别名。

如果你这样做:

 struct Foo; struct Foo {}; 

它工作,因为你在这两种情况下声明一个名为Foo的结构。

你不能转发声明匿名结构。 您剩下两个select:包括整个定义,或更改标题并命名结构。

你不需要在C ++中input结构体:

 struct Foo; // Forward declaration struct Foo { }; // Definition 

如果你想在C中调用Foo而不是struct Foo ,你需要typedef,这也可以通过不同的方式来完成:

 struct Foo; /* Forward declaration */ struct Foo /* The name is needed here */ { }; /* Definition */ typedef struct Foo Foo; /* typedef */ 

要么

 struct Foo; /* Forward declaration */ typedef struct Foo /* The name is needed here */ { } Foo; /* Definition and typedef combined */ 

你当然可以在C和C ++中使用struct Foo的forms。

您的前向声明声明将会有一个名为Foostruct

你的第二个声明是一个名为Footypedef 。 这些不是一回事。

在类似的情况下,我有一个类似的传统C头

 == old_library.h == typedef struct { int data; } Foo; == /old_library.h == 

我在我自己的C ++类中使用它作为私有方法的参数:

 class C { void run(Foo *ds); ... } 

为避免C.hpp中的#include“old_library.h”,我使用了下面的前向声明:

 class C { struct Foo; void run(Foo *ds); ... } 

在C.cpp中我有以下陈述:

 extern "C" { #include "old_library.h" } struct C::Foo : public ::Foo {}; 

这样,我使用C :: Foo而不是Foo透明,并且不需要MyFoo!

对于typedef的前向声明,您需要引用正在进行typedeff的事情,例如:

 struct foo; typedef foo bar; class foo{}; 

既然你想转发声明一个匿名结构,你既不能在原始实体的前向声明中给它一个名字,也不能在对它进行typedefing时引用它。 “逻辑”的语法是:

 struct ; typedef bar; class {}; 

但是由于这显然是不可能的,所以你不能转发声明匿名结构。

去标准化,让我们来看看9.1-2:

仅由类别密钥标识符组成的声明; 是在当前范围内对名称的重新声明或者将该标识符的前向声明作为类名称。 它将类名引入当前范围。

没有标识符,没有前向声明。

底线是:避免匿名结构,除非他们给你一个你真正需要的优势。

恕我直言,只需改变你的typedef

 typedef struct Foo {} Foo; ^^^^^ 

没有任何伤害,并且在C&C ++中仍然兼容。 现在你可以转发声明。

[注意:如果你仍然坚持不要触摸typedef ,那么这是一个肮脏的伎俩

 struct Foo; #define struct struct Foo #include"Foo.h" // contains typedef struct {} Foo; #undef struct 

只有Foo.h只包含1个struct声明,这才能工作。 我不推荐它。]

你的具体编译器可能在这里有所作为。

使用MinGW GCC 3.4.5,这两个声明都编译时没有错误或警告(使用-Wall

 struct Foo; typedef struct {} Foo; 

 struct Foo; typedef struct Foo {} Foo; 

图书馆内部是否存在前向声明? 例如,要允许一个圆形指针:

 struct Foo; typedef struct Foo { struct Foo *fooPtr; } Foo; 

如果这个已经存在于库头文件中,就会导致你描述的错误。

你为什么不避免前进decl。

如果第二个定义是在一个头文件中,你可以在你的C ++头文件中首先包含头文件。 为了使C ++认为它是C头,在大多数情况下,包含extern "C" {} #include必须足够。

我想我最近遇到了和原来的海报一样的问题,并解决了这个问题,如下:

我正在编写一个封装第三方提供的API定义为:

foo.h中:

 typedef struct _foo { int i; } Foo; Foo* MakeFoo(); int UseFoo(Foo* foo); 

我的包装需要有Foo作为成员,但我不想将Foo暴露给我的包装的所有消费者。

UberFoo.h:

 #pragma once struct _foo; // forward declare the actual type _foo, not the typedef Foo class UberFoo { public: UberFoo(); int GetAnswer(); private: _foo* f; }; 

UberFoo.cpp:

 #include "UberFoo.h" #include "Foo.h" UberFoo::UberFoo() { this->f = MakeFoo(); } int UberFoo::GetAnswer() { return UseFoo(f); } 

现在,我的类的消费者可以实例化它,而无需访问_foo / Foo的实际定义。 这也将工作,如果我需要传递指针_foo作为参数或返回从函数以及有一个成员_foo。

main.cpp中:

 #include <cstdio> #include "UberFoo.h" int main(int argc, char* argv[]) { UberFoo u; printf( "The Answer = %d\n", u.GetAnswer()); return 0; } 

这里的诀窍是转发声明实际的结构types,而不是typedef'd名称。 请注意,结构不是匿名的,这在旧的C代码中很常见:

 typedef struct // the actual struct type underlying the typedef is anonymous here { int i; } ThisWontWork; 

希望这可以帮助!

你不能转发声明它,因为它没有命名。 它是一个未命名的结构,为此Foo是一个typedef。

您正在尝试键入一个以前使用的名称。 该声明是完全有效的,只有你需要使用一个不同的名字。

 struct Foo; // Forward declaration of struct Foo typedef struct {} anotherFoo; // Another structure typedefed struct Foo { // Variables }; // Definition of the forward declared Foo. 

请注意,typedef不能用于相同的名称。