未命名结构的前向声明

发布于 2024-12-02 04:30:32 字数 359 浏览 0 评论 0原文

赏金问题:因此,这两个 Foo 不是同一件事。美好的。第二种形式是在图书馆中提供的。 如果我无法更改它,我如何前向声明它?


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

struct Foo;
typedef struct {} Foo;

这会产生以下错误:

“struct Foo”之前有一个声明为“struct Foo”

我想转发声明,该死!这是怎么回事?

Bounty question: So, these two Foos aren't the same thing. Fine. The second form is given in a library. How do I forward-declare it given that I can't change it?


I always thought C and C++ allowed repeated declarations provided that there were no repeated definitions. Then I came across this problem when trying to write C++ code which extends a C library.

struct Foo;
typedef struct {} Foo;

This gives the following error:

'struct Foo' has a previous declaration as 'struct Foo'

I want to forward-declare, darn it! What's wrong here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

纵情客 2024-12-09 04:30:33

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

您的第二个声明是名为 Footypedef。这些不是同一件事。

Your forward declaration declares that there will be a struct called Foo.

Your second declaration is of a typedef called Foo. These are not the same thing.

困倦 2024-12-09 04:30:33

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

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

由于您想要前向声明一个匿名结构,因此您既不能在原始实体的前向声明中给它一个名称,也不能给它一个名称。你可以在定义它时参考它。 “逻辑”语法是:

struct ;
typedef bar;
class {};

但由于这显然是不可能的,因此您不能转发声明匿名结构。

为了标准化,让我们看一下 9.1-2:

仅由类键标识符组成的声明;是一个
在当前作用域或前向作用域中重新声明名称
将标识符声明为类名。它介绍了班级
名称进入当前范围。

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

底线是:避免使用匿名结构,除非它们给你带来了你真正需要的优势。

For a forward declaration of a typedef, you need to refer to the thing that is being typedeffed, so like:

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

Since you want to forward declare an anonymous struct, you can neither give it a name in the forward declaration of the original entity, nor can you refer to it when typedefing it. The "logical" syntax would be:

struct ;
typedef bar;
class {};

But since this is obviously not possible, you can not forward declare anonymous structs.

To go standardese, lets have a look at 9.1-2:

A declaration consisting solely of class-key identifier; is either a
redeclaration of the name in the current scope or a forward
declaration of the identifier as a class name. It introduces the class
name into the current scope.

No identifier, no forward declaration.

Bottom line of this: avoid anonymous structs unless they give you an advantage that you really need.

〆一缕阳光ご 2024-12-09 04:30:33

您的特定编译器可能会有所不同。

使用 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;

如果库标头中已存在循环指针,则会导致您描述的错误。

Your specific compiler may make a difference here.

Using MinGW GCC 3.4.5, both declarations compile with no errors or warnings (using -Wall)

struct Foo;
typedef struct {} Foo;

and

struct Foo;
typedef struct Foo {} Foo;

Is it possible a forward-declaration already exists inside the library? For instance, to allow a circular pointer:

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

If this already exists within the library headers, it would cause the error you describe.

北城半夏 2024-12-09 04:30:33

恕我直言,只需将您的 typedef 更改为,

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

没有任何害处,并且它仍然在 C 和 C 语言中兼容。 C++。现在您可以转发声明了。

[注意:如果您仍然坚持根本不接触 typedef,那么这里是一个肮脏的伎俩

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

仅当 Foo.h 仅包含 1 个 struct 声明时,此方法才有效。我不推荐它。]

IMHO, simply change your typedef to,

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

There is no harm and it will still compatible in both C & C++. Now you can forward declare it.

[Note: If you still insist on on not touching the typedef at all then here is the dirty trick.

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

This will work, only if Foo.h contains only 1 struct declaration. I don't recommend it.]

混浊又暗下来 2024-12-09 04:30:33

我想我最近遇到了与原始海报相同的问题,并已解决如下:

我正在围绕第三方提供的 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;
}

这里的技巧是转发声明实际的结构类型,而不是 typedef 的名称。请注意,结构不能是匿名的,这一点很重要,这在旧的 C 代码中很常见:

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

希望这会有所帮助!

I think I recently ran into the same problem as the original poster, and have resolved it as below:

I am writing a wrapper around a third-party provided API defined as:

Foo.h:

typedef struct _foo 
{
    int i;
} Foo;

Foo* MakeFoo();
int UseFoo(Foo* foo);

My wrapper needs to have Foo as a member, but I don't want to expose Foo to all consumers of my wrapper.

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

Now, the consumers of my class can instantiate it without having access to the actual definition of _foo/Foo. This would also work if I needed to pass pointers to _foo as parameters or return them from functions as well as having a member _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;
}

The trick here was to forward declare the actual struct type, not the typedef'd name. Note that it is critical that the struct not be anonymous, as is common in older C code:

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

Hope this helps!

您无法转发声明它,因为它未命名。它是一个未命名的结构,其中 Foo 是一个 typedef。

You can't forward declare it, since its unnamed. Its an unnamed struct, for which Foo is a typedef.

苦行僧 2024-12-09 04:30:33

你为什么不直接避免前向减速呢?

如果第二个定义位于头文件中,则可以首先将头文件包含在 C++ 头文件中。为了让 C++ 将其视为 C 标头,在大多数情况下,用 extern "C" {} 包含 #include 就足够了。

Why don't you just avoid forward decl.

If the second definition was in a header file, you could include the header file first in your C++ header file. To make C++ think it as C header, embracing #include with extern "C" { and } must be suffice in most case.

苍风燃霜 2024-12-09 04:30:33

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

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

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

You are trying to typedef a previously used name. The statement is perfectly valid, only you need to use a different name.

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

Note that the typedef cannot be used in the same name.

泪眸﹌ 2024-12-09 04:30:32

typedef-ing 匿名结构是 C++03 之前的一种做法,主要是为了保持与 C99 之前的编译器的兼容性。

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

如果它不再处于开发阶段,你就不能“离开”,而只能“生存”并改变它,这就是做到这一点的方法。
如果仍在部署中,请将问题提交给开发团队。

如果您需要解决方法,请考虑结构可以继承。
因此,编写一个前向声明

struct MyFoo;

,并将其定义为

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

在所有代码中,忘记 Foo 并始终使用 MyFoo

typedef-ing anonymous struct is a practice that pre-dates C++03 and is mainly oriented to retain compatibility with pre-C99 compilers.

Given that this is 2011, and that both C++ and C are changed, I wonder why there is no more up-to-date version of such a library!

If it is not in development anymore, you cannot "leave", but just "survive" and change it is the way to do that.
If still in deployment, submit the issue to the development team.

If you need a workaround, consider that struct can inherit.
So, write a forward declaration like

struct MyFoo;

and define it as

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

And in all your code, forget about Foo and always use MyFoo.

高跟鞋的旋律 2024-12-09 04:30:32

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

如果您这样做:

struct Foo;
struct Foo {};

它可以工作,因为您在这两种情况下都声明了一个名为 Foo 的结构。

您不能转发声明匿名结构。您有两个选择:包含整个定义,或者更改标头并命名结构。

You're declaring two different entities with the same name. The first, struct Foo, is a struct named Foo. The second is an alias for an anonymous struct.

If you do instead:

struct Foo;
struct Foo {};

It works, because you're declaring a struct named Foo in both situations.

You cannot forward declare anonymous structs. You're left with two choices: include the whole definition, or change the header and name the struct.

孤独难免 2024-12-09 04:30:32

在类似的情况下,我有一个遗留的 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!

In a similar situation, I have a legacy C header with something like

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

I use it in a C++ class of my own, as parameter for a private method:

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

To avoid #include "old_library.h" from C.hpp, I use the following forward declaration:

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

and in C.cpp I have the following statements:

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

This way, I use C::Foo instead of Foo transparently, and don't need a MyFoo!

葮薆情 2024-12-09 04:30:32

您不需要在 C++ 中键入定义结构:

struct Foo;     // Forward declaration

struct Foo 
{

}; // Definition

如果您只想调用它 Foo 而不是 C 中的 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 形式。

You don't need to typedef structs in C++:

struct Foo;     // Forward declaration

struct Foo 
{

}; // Definition

If you want to call it just Foo instead of struct Foo in C, you do need the typedef, which can also be done in different ways:

struct Foo;     /* Forward declaration */

struct Foo /* The name is needed here */
{

}; /* Definition */
typedef struct Foo Foo;  /* typedef */

or

struct Foo;     /* Forward declaration */

typedef struct Foo /* The name is needed here */
{

} Foo; /* Definition and typedef combined */

You can of course use the form struct Foo in both C and C++.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文